Skip to content

Laravel Token Guard Auth Bypass: Check and Fix

Critical Laravel TokenGuard auth bypass (CVSS 9.2). Check if you use the token driver, update to 13.29 or 12.68, and see why MySQL makes it work.

Dasun Kalupahana 5 min read 106 views 0 comments
On this page
  1. The short version
  2. Step 1: check whether you use the token guard
  3. Step 2: update
  4. Versions: what I verified in the source
  5. Why it happens
  6. What about hashed tokens?
  7. If you can't update today
  8. A second, smaller fix in the same release
  9. Sources

A critical vulnerability in Laravel's built-in token API guard lets an unauthenticated visitor log in as an existing user without knowing that user's token. The Laravel team fixed it in August 2026, but the advisory only went public on 19 October 2026, and details and a public proof of concept followed within days. It is rated CVSS 9.2. Most modern Laravel apps are not exposed, because the guard has to be switched on in your config, but if yours is, this is a same-day update. Below: who is affected, a 2-minute check, the fix, and why it happens. I confirmed the root cause on a real MariaDB database and compared the code before and after the fix.

The short version

  • What: authentication bypass in Illuminate\Auth\TokenGuard, tracked as GHSA-f9x3-7vq9-cph6, CVSS v4.0 9.2.
  • Who: apps that use a guard with 'driver' => 'token' in config/auth.php, with users stored in MySQL or MariaDB.
  • Fix: update laravel/framework to 13.29.0 or newer (13.x), or 12.68.0 or newer (12.x).
  • Not listed as affected: Sanctum and Passport, which register their own guards. The session guard is not listed either.
  • Exploitation: a public proof of concept has been reported. As of the latest report I found (Cyber Kendra, 21 October), no attacks in the wild had been seen.

Step 1: check whether you use the token guard

# 1. Is a guard using the token driver?
grep -n "'driver' => 'token'" config/auth.php

# 2. Which framework version is installed?
composer show laravel/framework | grep versions

# 3. Does Composer already know about this advisory?
composer audit

If the first command prints nothing, you are not using the vulnerable guard. Also check routes protected with something like auth:api and make sure that guard is not the token driver. Older Laravel skeletons (up to about Laravel 7) shipped an api guard with the token driver, so long-lived apps are the most likely to still have it. If composer audit lists GHSA-f9x3-7vq9-cph6, you have the confirmation.

Step 2: update

composer update laravel/framework
composer show laravel/framework | grep versions

You want 13.29.0+ on Laravel 13 or 12.68.0+ on Laravel 12. Then deploy and restart your PHP workers. The advisory offers no other workaround, so do not treat a rule in a firewall as a replacement.

Versions: what I verified in the source

Sources disagree on version details, so I compared the actual code in the tagged releases. The fix is a type check in TokenGuard.php:

ReleaseHas the is_string() check?
13.26.1 and olderNo
13.27.0, 13.28.0, 13.29.0Yes
12.67.0No
12.68.0Yes
11.56.0No
11.56.1Yes
10.49.0No

The code change appears from 13.27.0 on, but the advisory and Laravel News list 13.29.0 as the fixed version for Laravel 13, so move to 13.29.0 or newer and you are covered either way. The fix commit is dated 24 August 2026 and the releases 25 August 2026. On Laravel 11, one report says no patch exists while another lists 11.56.1; the source shows 11.56.1 does contain the check. On 10.x, the release I checked (10.49.0) has no fix, so check the advisory for your branch or upgrade to a supported version.

Why it happens

The explanation below follows the published analysis, and I tested each link in the chain.

  1. Before the fix, the guard only checked that the incoming token was not empty. It did not check that it was a string.
  2. A non-string value, such as a list, passes that check and reaches the user lookup, where it is turned into a database query with a list of values.
  3. MySQL and MariaDB compare text columns with numbers by converting the text to a number, and text that does not start with a digit becomes 0.

Step 3 is easy to confirm yourself without any exploit. On MariaDB, with two users whose tokens start with letters, I ran three queries:

QueryRows matched
where api_token = 02 (every user)
where api_token in (0)2 (every user)
where api_token = '0'0

A numeric value matched every row, and the same value as text matched none. So a non-string "token" can match a real user's row, which is why the guard authenticates someone who never knew the real token. According to the analysis, the attacker cannot choose which user they become, but that is little comfort when one of them is an admin. This is also why the advisory is specific to MySQL and MariaDB; I did not test other databases, so I cannot tell you they are safe.

I also compared the guard code before (13.26.1) and after (13.29.0), using a stub user provider that records what reaches the database. Before the fix, a non-string token was passed to the provider and the guard resolved a user. After the fix, validate() returned false, user() returned null, and nothing non-string reached the provider. That is a unit-level check with a stand-in provider, not a test against a running app.

What about hashed tokens?

If your guard has 'hash' => true, an array token makes PHP's hash() throw a TypeError in the user() path (I confirmed that call fails with an array). That produces an error instead of a match, but the advisory does not exempt hashed setups, so update regardless.

If you can't update today

There is no official workaround. The practical steps are to check whether you really use the guard, and if you do not need it, remove the token guard from config/auth.php so no route can use it. In the longer term, consider moving API authentication to Sanctum, which is not listed as affected. Review access logs for unusual successful logins on token-protected routes, and treat accounts that never should have been reachable as suspect.

A second, smaller fix in the same release

Laravel News also reports a medium-severity issue (CVSS 6.5, GHSA-5wcm-3v2w-8362) in the JSON:API resources added in Laravel 12.45, where a read-only request could trigger a destructive operation on a related table. It is fixed in 13.27.0 and 12.68.0, so the same update covers it. I did not test this one.

Sources

Free resources for this topic

Code snippets and fixes for this topic

Get one practical tip every week

New tutorials, fixes and free cheat sheets from DEV Talk, straight to your inbox. No spam, unsubscribe in one click.

Free download: Laravel interview questions (PDF)

Have a question about this post?

Ask the community: other developers and the author can answer.

Ask the community

Get notified about new articles

One click, no email needed. Turn it off anytime with the bell at the top.

Get new articles on your iPhone

Add DEV Talk to your Home Screen, open it, then tap the bell.

Rate this post
0.0
Share

Enjoying the content?

If this article helped you, you can support the author with a coffee. It keeps new posts coming.

Buy me a coffee (opens in a new tab)

Comments 0

Be kind. Comments with links are reviewed before they appear.

No comments yet

Be the first to share your thoughts.

Get new articles in your inbox

Practical tutorials and deep dives, about once a week. No spam, unsubscribe anytime.

Privacy policy

Add DEV Talk to your Home Screen

  1. 1 Tap the Share button in Safari's toolbar.
  2. 2 Scroll down and tap Add to Home Screen.
  3. 3 Tap Add. Open it from the Home Screen to read like an app and to turn on notifications with the bell.

We use cookies to improve your experience and analyze traffic. By continuing, you agree to our Privacy Policy.