Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-39923

CVE-2026-39923: Flarum Auth Bypass Vulnerability

CVE-2026-39923 is an authentication bypass flaw in Flarum that allows attackers to reuse expired password reset tokens to take over accounts. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-39923 Overview

CVE-2026-39923 is a password reset token expiry bypass vulnerability in Flarum forum software before version 1.8.16. The flaw resides in the SavePasswordController::handle() method, which calls PasswordToken::findOrFail() without validating token expiry. Attackers can reuse expired password reset tokens by submitting them directly to the reset processing endpoint, bypassing the 24-hour token lifetime enforced only during form rendering. Successful exploitation allows unauthenticated attackers to change any account's password and obtain an authenticated session. The issue is tracked under [CWE-324: Use of a Key Past its Expiration Date].

Critical Impact

Unauthenticated attackers can hijack any Flarum account, including administrators, by replaying expired password reset tokens against the reset endpoint.

Affected Products

  • Flarum framework versions prior to 1.8.16
  • Flarum core package (flarum/core)
  • Flarum-based forums that have not applied the security patch in pull request #4545

Discovery Timeline

  • 2026-08-05 - CVE-2026-39923 published to NVD
  • 2026-08-05 - Last updated in NVD database

Technical Details for CVE-2026-39923

Vulnerability Analysis

The vulnerability exists in Flarum's password reset workflow. The application generates a PasswordToken with a 24-hour lifetime and validates that expiry only when rendering the password reset form. When a user submits the new password, the request reaches SavePasswordController::handle(), which retrieves the token via PasswordToken::findOrFail(). This lookup performs no expiry check. An attacker who obtains any historical, unused password reset token, whether from log files, backups, browser history, referrer leakage, or intercepted email, can replay it directly against the reset endpoint indefinitely until the token record is removed from the database.

Root Cause

The root cause is inconsistent enforcement of token lifetime between the form rendering path and the form submission path. The findOrFail() method only checks that a token record exists. It does not compare the token's created_at timestamp against the 24-hour expiry window, breaking the security assumption that expired tokens are unusable.

Attack Vector

An unauthenticated attacker submits a POST request to the password reset processing endpoint with an expired passwordToken value and a chosen new password. Because the controller skips expiry validation, the server accepts the token, resets the account password, and issues an authenticated session cookie. The attack requires no user interaction after token acquisition and works against any account with a lingering reset token in the database.

php
// Vulnerable code (before patch) in SavePasswordController.php
$input = $request->getParsedBody();

-        $token = PasswordToken::findOrFail(Arr::get($input, 'passwordToken'));
+        /** @var PasswordToken $token */
+        $token = PasswordToken::validOrFail(Arr::get($input, 'passwordToken'));

$password = Arr::get($input, 'password');

Source: GitHub Commit 2803058

The patch introduces a new validOrFail() method on the PasswordToken model that raises InvalidConfirmationTokenException for expired tokens:

php
use Carbon\Carbon;
use Flarum\Database\AbstractModel;
+use Flarum\User\Exception\InvalidConfirmationTokenException;
use Illuminate\Support\Str;

/**
 * @property string $token
 * @property \Carbon\Carbon $created_at
 * @property int $user_id
+ * @method static self validOrFail(string $token)
 */
class PasswordToken extends AbstractModel

Source: GitHub Commit 2803058

Detection Methods for CVE-2026-39923

Indicators of Compromise

  • POST requests to the Flarum password reset submission endpoint (typically /reset) using passwordToken values older than 24 hours.
  • Unexpected password change events followed by successful logins from unfamiliar IP addresses or user agents.
  • Multiple passwordToken submissions reusing the same token value across different sessions.
  • Administrator account authentications not preceded by a legitimate password reset request in application logs.

Detection Strategies

  • Correlate password_tokens table records with reset submission timestamps to identify tokens used after their 24-hour window.
  • Alert on any password reset completion where the corresponding created_at for the token exceeds 86400 seconds before the submission time.
  • Review web server access logs for POST requests to the reset endpoint with tokens that were issued to accounts the requester does not own.

Monitoring Recommendations

  • Enable verbose logging on the Flarum authentication and password reset controllers to capture token identifiers and source IPs.
  • Forward web application logs to a centralized SIEM for retention and correlation with authentication events.
  • Monitor administrator and moderator account activity for unexpected password changes and session creation.

How to Mitigate CVE-2026-39923

Immediate Actions Required

  • Upgrade Flarum to version 1.8.16 or later immediately using Composer.
  • Invalidate all outstanding password reset tokens by truncating the password_tokens table after the upgrade.
  • Force password resets for administrator and privileged accounts that may have had reset tokens issued recently.
  • Review authentication logs for suspicious password changes and session establishments during the exposure window.

Patch Information

The fix is delivered in Flarum Release v1.8.16 via Pull Request #4545. The patch replaces PasswordToken::findOrFail() with a new PasswordToken::validOrFail() method that enforces the 24-hour expiry check on submission. Additional detail is available in the VulnCheck Security Advisory.

Workarounds

  • If immediate patching is not feasible, schedule a recurring job that deletes rows from the password_tokens table older than 24 hours.
  • Restrict access to the password reset endpoint using a web application firewall rule that rejects submissions where the token issuance time exceeds the expiry window.
  • Temporarily disable the self-service password reset feature and process resets manually through administrator tooling.
bash
# Upgrade Flarum core to the patched release
composer require flarum/core:^1.8.16 --update-with-dependencies
php flarum migrate
php flarum cache:clear

# Purge stale password reset tokens (MySQL example)
mysql -u flarum_user -p flarum_db -e \
  "DELETE FROM password_tokens WHERE created_at < (NOW() - INTERVAL 24 HOUR);"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.