Developer platforms, tools and supply chain

Laravel: CVE-2026-114509 TokenGuard authentication bypass

Laravel TokenGuard check

Laravel's built-in token guard ('driver' => 'token') does not reject a crafted non-string credential. A request such as {"api_token": [0]} reaches the database lookup, and on MySQL and MariaDB the lookup can match an unintended existing user. An unauthenticated attacker can then sign in as that user on any route protected by the token guard and take over the account. The reporter, Hristijan Manasijev, described it as a login as an existing victim user.

CVE CVE-2026-114509 (GitHub advisory GHSA-f9x3-7vq9-cph6, published 19 October 2026)
Severity 9.2 Critical (CVSS 4.0)
Affected laravel/framework below 12.68.0, and 13.0.0 up to 13.29.0
Fixed 12.68.0 and 13.29.0, both released 25 August 2026, nearly two months before the advisory. The 11.x branch carries the same is_string() check from v11.56.1, although the advisory does not list it
Move to 12.68.0, 13.29.0 or, on 11.x, 11.56.1 or later: 10.x and 9.x apps upgrade to one of them
Needs A guard that uses the token driver, routes that use it, and MySQL or MariaDB
Not the target Apps that authenticate with Laravel Sanctum or Laravel Passport, which register their own guard drivers
Exploited None confirmed, and no public proof of concept confirmed, as of 21 October 2026

The fix is two lines: the guard now requires is_string($token) before it queries the database.

Quick start

  1. Download the script. The repository is mirrored on GitHub and Codeberg; pick a base URL.

    # BASE from GitHub:   https://raw.githubusercontent.com/PrivacySafe/security-patches/refs/heads/main
    # BASE from Codeberg: https://codeberg.org/PrivacySafe/security-patches/raw/branch/main
    # curl -fLO "$BASE/laravel/laravel-tokenguard-check.sh"
    curl -fLO https://raw.githubusercontent.com/PrivacySafe/security-patches/refs/heads/main/laravel/laravel-tokenguard-check.sh
    
  2. Read it before running it, then make it executable.

    less laravel-tokenguard-check.sh
    chmod +x laravel-tokenguard-check.sh
    
  3. Check this host. By default it searches /var/www /srv /home /opt; pass directories to narrow it.

    ./laravel-tokenguard-check.sh check
    ./laravel-tokenguard-check.sh check /var/www/myapp
    
  4. If you cannot upgrade today, print the protective middleware.

    ./laravel-tokenguard-check.sh middleware > app/Http/Middleware/RejectNonStringApiToken.php
    

Commands

Command What it does
check [DIR ...] (default) Finds composer.lock files, reads the framework version from vendor/laravel/framework when it is installed (it wins over the lock file) and otherwise from composer.lock, then reads config/auth.php for guards that use the token driver, looks for routes and code that use those guards, and reads DB_CONNECTION from .env
middleware Prints a protective PHP middleware to standard output. It changes nothing by itself
version Prints the script version

Exit codes: 0 nothing exposed, 1 an affected project looks exposed or is on a branch with no upstream fix, 2 bad arguments.

How to read the result

  • Affected version, token guard in use, MySQL or MariaDB: exposed. Upgrade.
  • Affected version and no token guard: the vulnerable path is not in use. The script still warns, because custom code could construct a TokenGuard directly.
  • Token guard defined but nothing references it: a warning. This is a text search of routes, app and bootstrap, so a guard selected some other way can be missed.
  • Other database: the advisory describes the bypass on MySQL and MariaDB. The script prints a warning and still recommends upgrading. A project with an unknown database driver is treated as exposed.
  • 9.x and 10.x: affected. Upgrade to 12.68.0, 13.29.0 or, on 11.x, 11.56.1 or later.

Many older skeletons ship an api guard with the token driver in config/auth.php whether or not the app uses it. That is why the script looks for routes that use the guard before calling a project exposed.

The protective middleware

middleware prints a class that returns HTTP 401 when api_token arrives as an array or any other non-string value in the query string, the form body or a JSON body. Register it as global middleware that runs before authentication ($middleware->prepend(...) in bootstrap/app.php on Laravel 11 and newer, the first entry of $middleware in app/Http/Kernel.php on older versions). It blocks the crafted input described in the advisory. It is not the fix, and the advisory itself offers no workaround other than upgrading.

Sources

Before you run it

  • The fix. Update laravel/framework to 12.68.0, 13.29.0 or, on 11.x, 11.56.1 or later. Apps on 10.x and 9.x upgrade to one of those releases.
  • It only matters with the built-in token guard. Apps using Laravel Sanctum or Passport register their own guard drivers and are not the target of this bug. The script reads composer.lock and the installed copy, config/auth.php for a guard with the token driver, the routes that use it, and the database driver in .env (the lookup match needs MySQL or MariaDB).
  • The middleware command prints a protective middleware to stdout only. It is for apps that cannot upgrade today. The upgrade is the permanent fix.
  • There is no hunt. No indicators of exploitation have been published.
  • It also checks running docker and podman containers, unless you name a directory or set SCAN_CONTAINERS=0. In each running container, a read-only probe lists the project files this check needs: lockfiles, package.json, route directory names, the few source files that contain 'use server', config/auth.php and similar. Only those files are copied into a private temporary folder, and the normal check judges that folder like a host directory. .env is never copied: the probe reads only the one DB_CONNECTION= line and writes just that line into a minimal .env, so a database password or APP_KEY stays in the container. A staged symlink is never kept, paths the container reports are validated, and nothing is run in a container beyond find, grep and test. The copies are removed on exit. A path shown as .../docker_NAME/PATH is the PATH inside the container NAME. It is skipped when you name directories yourself.

The Security Patches software and this documentation are dedicated to the public domain under CC0 1.0 Universal. Other pages on privacysafe.app/docs are CC BY-SA 4.0 unless the page says otherwise.

Edit this page on Codeberg

The PrivacySafe Ecosystem

Shop at Ivy Cyber

Ivy Cyber offers PrivacySafe products and services in the USA and has partnerships with 3NSoft in Canada and Kuip Limited in the European Union. Enterprise services and consulting are available at ivycyber.com

PrivacySafe Foundation is a 501(c)(3) nonprofit public charity that supports the development of the PrivacySafe applications, along with the components they rely upon: 3NWeb protocols, filesystem, documentation, and reference implementations.

PrivacySafe Foundation

Donations to PrivacySafe Foundation support education, research, documentation, and public code. Purchases from Ivy Cyber support PrivacySafe products, services, hosting, and technical support. Together, we're building a better web.