Skip to content

[13.x] Guard against non-string mac in maintenance bypass cookie - #61314

Merged
taylorotwell merged 1 commit into
laravel:13.xfrom
KIKOmanasijev:fix/maintenance-bypass-cookie-mac-type
Aug 24, 2026
Merged

taylorotwell merged 1 commit into
laravel:13.xfrom
KIKOmanasijev:fix/maintenance-bypass-cookie-mac-type

Conversation

@KIKOmanasijev

Copy link
Copy Markdown
Contributor

MaintenanceModeBypassCookie::isValid() checks that the mac in the decoded cookie is set, but not that it's actually a string. If someone sends a laravel_maintenance cookie whose mac is an array, isset() still passes and the array is handed straight to hash_equals(), which throws a TypeError. While maintenance mode is active with a secret, that turns into an unauthenticated 500 instead of the expected 503.

Reproduction, using an array for mac:

$cookie = base64_encode(json_encode(['expires_at' => 9999999999, 'mac' => []]));

MaintenanceModeBypassCookie::isValid($cookie, $key);
// TypeError: hash_equals(): Argument #2 must be of type string, array given

The fix swaps the isset() check for is_string(), matching the is_numeric() guard already used for expires_at right above it. A non-string mac now just fails validation and the request gets the normal 503.

return is_array($payload) &&
    is_numeric($payload['expires_at'] ?? null) &&
    is_string($payload['mac'] ?? null) &&
    hash_equals(hash_hmac('sha256', $payload['expires_at'], $key), $payload['mac']) &&
    (int) $payload['expires_at'] >= Carbon::now()->getTimestamp();

@taylorotwell
taylorotwell merged commit 4302a3d into laravel:13.x Aug 24, 2026
56 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants