Skip to content

Fatal 500: CSRF token not initialized for existing sessions — hash_equals() TypeError #1285

@thvevirtue

Description

@thvevirtue

Bug Report

Summary

A PHP fatal error (HTTP 500) occurs when a logged-in user with an existing session (one that pre-dates CSRF token generation, or after a partial session reset) tries to submit any form containing a CSRF token field.

Steps to Reproduce

  1. Have a user with an active session ($_SESSION['client_logged_in'] = true) that does not contain a csrf_token key.
  2. Navigate to /client/ticket_add.php (or any page rendering <?= $_SESSION['csrf_token'] ?>).
  3. Submit the form.

Expected Behaviour

User is redirected with a friendly "session expired" message and prompted to retry.

Actual Behaviour

PHP Fatal Error → HTTP 500:

PHP Warning:  Undefined array key "csrf_token" in client/ticket_add.php on line 28
PHP Warning:  Undefined array key "csrf_token" in functions.php on line 650
PHP Fatal error: Uncaught TypeError: hash_equals(): Argument #2 ($user_string) must be of type string, null given in functions.php:650

Root Cause

$_SESSION['csrf_token'] is only set in login.php after a successful login. Neither includes/check_login.php nor client/includes/check_login.php check for or regenerate a missing token. validateCSRFToken() in functions.php passes the value directly to hash_equals() with no null/type guard, causing a fatal TypeError when the token is null.

Affected Files

  • functions.phpvalidateCSRFToken() lacks a null/type check before hash_equals()
  • includes/check_login.php — never regenerates a missing CSRF token for active sessions
  • client/includes/check_login.php — same issue

Suggested Fix

1. Add a null guard to validateCSRFToken() in functions.php:

function validateCSRFToken($token)
{
    if (!is_string($token) || empty($token) || empty($_SESSION['csrf_token'])) {
        $_SESSION['alert_type'] = 'warning';
        $_SESSION['alert_message'] = 'Your session has expired or is invalid. Please try again.';
        header('Location: index.php');
        exit();
    }
    if (hash_equals($_SESSION['csrf_token'], $token)) {
        return true;
    } else {
        $_SESSION['alert_type'] = 'warning';
        $_SESSION['alert_message'] = 'CSRF token verification failed. Try again, or log out to refresh your token.';
        header('Location: index.php');
        exit();
    }
}

2. Ensure the token is always present at session check time (both check_login.php files):

// At the end of check_login.php, after all session validation passes:
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = randomString(32);
}

Environment

  • ITFlow self-hosted (latest stable)
  • PHP 8.x
  • Reproducible on the client portal (/client/) — likely also affects the agent portal for the same reason.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions