Skip to content

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

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

    Fields

    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