CVE-2026-39976
PHP vulnerability analysis and mitigation

Overview

CVE-2026-39976 is an authentication bypass vulnerability in Laravel Passport affecting versions 13.0.0 through 13.7.0, where machine-to-machine client_credentials tokens can inadvertently authenticate as real users. The league/oauth2-server library sets the JWT sub claim to the client identifier (since no user is associated), and Passport's TokenGuard passes this value directly to retrieveById() without validating it is a user identifier. This can cause an unrelated real user to be resolved, effectively allowing any client credentials token to impersonate an actual user. It was disclosed on April 8–9, 2026, and carries a CVSS v3.1 base score of 7.1 (High) (GitHub Advisory, Feedly).

Technical details

The root cause is improper authentication (CWE-287) in TokenGuard::authenticateViaBearerToken(), which passes the oauth_user_id PSR attribute directly to provider->retrieveById() without checking whether the value is actually a user identifier. For client_credentials grants, league/oauth2-server's AccessTokenTrait::getSubjectIdentifier() falls back to the client's UUID as the JWT sub claim, which BearerTokenValidator then maps into oauth_user_id. When the application uses MySQL with integer auto-increment primary keys, MySQL's implicit type casting converts the UUID string (e.g., 019c9d23-9763-7303-9bdb-3a0a6bf0xf90) to an integer (e.g., 19), causing User::find(19) to return a real user. The vulnerability is specifically triggered when Passport::$clientUuids is set to false (non-UUID client IDs) or when UUID-to-integer casting occurs at the database level (GitHub Issue #1900, GitHub Advisory).

Impact

A low-privileged attacker with a valid client_credentials token can silently authenticate as an arbitrary real user, gaining access to that user's data and permissions without their knowledge. This results in high confidentiality impact (unauthorized access to user data) and low integrity impact (ability to perform actions as the impersonated user), with no availability impact. The scope change in the CVSS score reflects that the vulnerability in the OAuth component affects resources (user accounts) outside its security boundary, potentially enabling lateral movement across user-scoped resources within the application (GitHub Advisory, Feedly).

Exploitability

A proof-of-concept with detailed reproduction steps is publicly available on GitHub, demonstrating the full exploitation flow (GitHub Issue #1900). The EPSS score is approximately 0.064%, indicating a currently low probability of widespread exploitation. There is no evidence of in-the-wild exploitation at this time, no known threat actor attribution, and the vulnerability is not listed in the CISA KEV catalog. Exploitation requires the attacker to already possess a valid client_credentials token (low privileges required) and the target application to use integer primary keys for users with MySQL, making it a high-complexity attack (Feedly).

Exploitation steps

  1. Reconnaissance: Identify a Laravel application using Passport v13.0.0–13.7.0 with the client_credentials grant enabled and MySQL with integer auto-increment primary keys for the users table.
  2. Obtain client credentials: Acquire a valid OAuth client ID and secret (e.g., through legitimate API registration or by compromising a machine-to-machine service account).
  3. Request a client_credentials token: Send a POST request to the token endpoint:
    POST /oauth/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=client_credentials&client_id=<CLIENT_ID>&client_secret=<CLIENT_SECRET>&scope=
  4. Identify target user: Determine a user whose integer ID matches the leading digits of the client UUID after MySQL type casting (e.g., client UUID 019c9d23-... casts to integer 19, targeting user ID 19).
  5. Use token to impersonate user: Include the obtained bearer token in API requests. When the application calls Auth::guard('api')->user() or $request->user(), the TokenGuard resolves the unrelated user instead of returning null, granting access to that user's data and permissions.
  6. Access user-scoped resources: Make authenticated API calls as the impersonated user to exfiltrate data or perform privileged actions (GitHub Issue #1900, GitHub Advisory).

Indicators of compromise

  • Logs: Application logs showing Auth::guard('api')->user() returning a non-null user for requests authenticated with client_credentials grant tokens; access log entries where machine-to-machine client tokens are used to access user-specific API endpoints.
  • Database: Unexpected access patterns in audit logs where a user account's data is accessed at times inconsistent with normal user activity, particularly correlated with OAuth client activity.
  • Application Behavior: API responses returning user-specific data (profile, settings, private resources) in contexts where only machine-to-machine access should be occurring; oauth_access_tokens records with user_id = NULL (client credentials) being used to access user-scoped routes (GitHub Issue #1900).

Mitigation and workarounds

Upgrade Laravel Passport to version 13.7.1 or later, which fixes the vulnerability by checking whether oauth_user_id equals oauth_client_id and the client uses the client_credentials grant type before returning null (GitHub Advisory, PR #1901, PR #1902). As a workaround for those unable to upgrade immediately, disable the client_credentials grant entirely. Applications using integer-based client IDs should also run the grant_types migration (referenced in issue #1913) to ensure the fix functions correctly. After patching, audit access logs for any suspicious authentication activity using client_credentials tokens that may have resulted in unintended user-level access.

Community reactions

The vulnerability was reported by community member MohZubiri on March 29, 2026, and the fix was contributed by pushpak1300 and reviewed by hafezdivandari, with Taylor Otwell merging the patches on April 1–2, 2026 (PR #1901, PR #1902). Security Online Info published a dedicated write-up on the vulnerability (Security Online). Community discussion on GitHub noted edge cases where the initial fix (PR #1901) could incorrectly reject legitimate user tokens when user and client IDs collide in integer-key setups, leading to the follow-up fix in PR #1902 and additional documentation updates.

Additional resources


SourceThis report was generated using AI

Related PHP vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

CVE-2026-59989CRITICAL9.2
  • PHP logoPHP
  • phalcon/cphalcon
NoYesAug 21, 2026
CVE-2026-63135HIGH8.2
  • PHP logoPHP
  • yourls/yourls
NoYesAug 21, 2026
GHSA-p2ch-c2c3-4xm5MEDIUM6.1
  • PHP logoPHP
  • winter/wn-backend-module
NoYesAug 20, 2026
GHSA-8hgv-xc77-jmcrMEDIUM5.1
  • PHP logoPHP
  • getgrav/grav
NoYesAug 21, 2026
GHSA-hq84-x37p-j6q5MEDIUM4.5
  • PHP logoPHP
  • winter/wn-backend-module
NoYesAug 20, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management