Welcome to HowToShipIt — practical how-to guides for developers: code, AI tools, and servers, explained step by step.

CVE-2026-114509: The Laravel TokenGuard Auth Bypass — Are You Actually Affected? (2026)

CVE-2026-114509 at a glance

CVE-2026-114509 is a critical authentication bypass in Laravel’s built-in TokenGuard, rated CVSS 9.2 (Critical, CVSS 4.0). An unauthenticated attacker can submit a crafted non-string credential that, on certain MySQL or MariaDB configurations, matches an unintended user record — authenticating as another user without ever knowing a valid API token. The issue is fixed in laravel/framework 12.68.0 and 13.29.0, and a working public proof of concept has been available since October 20, 2026.

Before you panic: this flaw does not affect every Laravel app. It needs three conditions to line up — the legacy token guard driver, a vulnerable framework version, and a MySQL/MariaDB-backed users table — and there is no confirmed exploitation in the wild as of 2026-10-23. This guide helps you answer the one question that matters: are you actually affected, and what do you do about it?

Fact Detail
CVE CVE-2026-114509 (published 2026-10-21)
Severity CVSS 9.2 Critical (CVSS 4.0), CWE-287 Improper Authentication
Affected laravel/framework < 12.68.0, and >= 13.0.0 < 13.29.0 (11.x before v11.56.1, per PoC authors)
Fixed in 12.68.0 / 13.29.0 (released August 25, 2026)
Advisory GHSA-f9x3-7vq9-cph6 (published 2026-10-19), reported by Hristijan “KIKO” Manasijev
Public PoC Yes — Hakai Security, October 20, 2026
Exploitation in the wild None confirmed as of 2026-10-23; not in CISA KEV; EPSS 0.4% (30-day)

How the attack works (the short version)

The flaw is a chain of three small defects, each harmless alone. First, pre-fix TokenGuard::user() only checked if (! empty($token)) before hitting the user provider. PHP’s empty() returns false for a non-empty array, so a JSON body like {"api_token": [0]} sailed straight through the gate — the guard never verified the credential was actually a string.

Second, EloquentUserProvider::retrieveByCredentials() converts any array value into a whereIn(), producing roughly select * from users where api_token in (?) limit 1. Third, because the payload arrives in a JSON body, json_decode produces a real PHP integer bound via PDO — and MySQL/MariaDB then compare the VARCHAR api_token column numerically. Any stored token that does not start with a digit casts to 0, so the lookup matches the first user whose token isn’t digit-leading. The guard then treats the request as fully authenticated: account takeover with zero knowledge of any token.

The patch is one line of common sense — if (is_string($token) && ! empty($token)) — which landed in the August 2026 releases. One subtle detail from the PoC authors’ write-up: the trick only works through a JSON request body. A query-string variant like ?api_token[]=0 produces the string '0', which never matches a stored token. So the attack requires the token guard plus a JSON credential body plus MySQL/MariaDB.

Why the public PoC raised the stakes

The advisory itself was published on October 19, 2026 (GHSA-f9x3-7vq9-cph6, credited to researcher Hristijan “KIKO” Manasijev via GitHub’s Security Advisory program), and the CVE was assigned on October 21. The Hakai Security write-up dropped on October 20 with the full treatment: root-cause analysis, links to the vulnerable commit (13.x#0189a60b) and the fix commit (13.x#9b21ce0a), a working Python exploit, a reproducible Docker lab on MySQL 8 — vulnerable app on port 8891, fixed app on port 8892, same database — and an 18-second recorded demo showing the attack succeeding on the vulnerable build and failing on the patched one. Italy’s national CSIRT warned on October 22 that the PoC was available. The PoC even supports targeting a specific user by id or email, and piping through Burp for inspection.

None of that changes whether you are affected — the three conditions below are still the whole story — but it does mean anyone scanning the internet for vulnerable Laravel APIs no longer has to guess at the exploit. The PoC is 11 stars on GitHub today; it won’t stay niche forever. EPSS currently estimates a 0.4% chance of exploitation in the next 30 days, which is low, but that number moves the moment someone starts scanning.

Step 1: Check which guard driver your API uses

This is the fastest filter. Only Laravel’s built-in token driver is in scope. Open config/auth.php and find your API guard:

'guards' => [
    'api' => [
        'driver' => 'token',
        'provider' => 'users',
    ],
],

If the driver is token, you are in the affected population — keep going. If your API uses 'driver' => 'sanctum' or 'driver' => 'passport', stop here: you are not in scope. Sanctum and Passport register their own guard drivers, and Laravel’s advisory explicitly excludes them. That single check clears the vast majority of modern Laravel APIs.

Step 2: Check your framework version

Run this in your project directory:

composer show laravel/framework

You are vulnerable if the installed version is < 12.68.0, or >= 13.0.0 and < 13.29.0. If you are still on Laravel 11.x, the PoC authors note you need at least v11.56.1. One nuance worth knowing: the actual fix commits first shipped in tags v13.27.0, v12.68.0, and v11.56.1 (Taylor Otwell authored them August 24–25, 2026), but the advisory conservatively designates 13.29.0 as the patched release — nothing touched TokenGuard.php between v13.27.0 and v13.29.0, so the advisory plays it safe. Either way, since the fixes shipped back in August 2026, any app that has been regularly updated is very likely already patched. Check before you sweat.

Step 3: Check your database engine

The type-coercion trick only works on MySQL or MariaDB. Check DB_CONNECTION in your .env or config/database.php:

grep '^DB_CONNECTION' .env

If it says mysql or mariadb and your users table lives there, the attack path is fully open. If you run PostgreSQL or SQLite behind the guard, the integer-coercion vector does not apply — though you should still upgrade on principle, since the guard was accepting non-string credentials at all.

Step 4: Patch it (upgrade — there is no workaround)

The advisory lists no workaround: upgrading is the fix. From your project root:

composer update laravel/framework
composer audit

Confirm you land on 12.68.0+ or 13.29.0+, then run composer audit to verify the advisories clear. If you pin versions in CI, bump the constraint there too — a composer install on a locked vulnerable version keeps you exposed. Redeploy, and you’re done.

If you cannot upgrade immediately (legacy constraints, frozen lockfile), be honest with yourself about the exposure: an attacker needs your API routes to accept JSON bodies with the token field — which is the default setup for a token-driver API. There is no mitigation short of the patched framework, so treat the upgrade as the same-day priority Italy’s national CSIRT treated the PoC release: patch first, review afterwards.

Step 5: If you were exposed before patching, check your logs

No exploitation has been confirmed in the wild as of 2026-10-23, and the flaw is not in CISA’s KEV catalog. But if you ran a vulnerable version behind TokenGuard on MySQL/MariaDB any time after the public PoC dropped on October 20, a quick review is cheap insurance: look for successful authentications on token-guarded routes from unfamiliar clients, and rotate your API tokens. The PoC’s expected vulnerable output is literally {"api_token": [0]} -> 200, so unexpected 200s on guarded endpoints during that window deserve a second look.

Bonus: the sibling advisory you might have missed

The same researcher, KIKO Manasijev, reported a second advisory on the same day: GHSA-5wcm-3v2w-8362 (CVSS 6.5, Medium). It affects Laravel’s JSON:API resources feature — a crafted request to a read-only endpoint can, under specific conditions, trigger a destructive database operation on a related table instead of just reading data. A user with only read access could cause irreversible data loss without any write permissions.

That one affects 12.x from 12.45.0 (when JSON:API resources landed) up to < 12.68.0, and 13.x < 13.27.0 — patched in 12.68.0 and 13.27.0. Since the same composer update that fixes CVE-2026-114509 also fixes this one, run the update once and clear both advisories. If your app exposes JSON:API resources with relationship inclusion, verify the fix with composer audit rather than assuming the version bump covered it.

The bottom line

CVE-2026-114509 is a genuinely critical bug with a public PoC — but its blast radius is narrow: the legacy token guard driver, a pre-August framework version, and MySQL/MariaDB. If you use Sanctum or Passport, you’re out of scope. If you patched after August 25, you’re already fixed. If all three conditions apply to you, the fix is a composer update — no workaround, no config change, no heroics required. The cheapest security incident is the one you patch before it becomes one.

Facts verified 2026-10-23 against the official Laravel security advisories, the Hakai Security PoC write-up and repository, laravel-news.com, and the live CVE record. No exploitation in the wild confirmed as of this writing.

Further Reading & References

Leave a Comment