
Cloud Vulnerability DB
A community-led vulnerabilities database
CVE-2026-53517 is a race condition vulnerability in the Better Auth OAuth provider library for TypeScript, allowing authenticated users to bypass refresh token revocation by exploiting concurrent token redemption. The flaw affects @better-auth/oauth-provider versions >= 1.6.0 and < 1.6.11, and the embedded plugin in better-auth versions >= 1.4.8-beta.7 and < 1.6.0. It was first published on May 31, 2026, added to the GitHub Advisory Database on July 7, 2026, and published by NVD on July 15, 2026. The vulnerability carries a CVSS v3.1 base score of 8.1 (High) and a CVSS v4.0 base score of 7.6 (High) (GitHub Advisory, Github Advisory).
The root cause is a non-atomic read/validate/revoke/mint sequence on the oauthRefreshToken database row in the POST /oauth2/token endpoint's refresh_token grant handler (CWE-362, CWE-367). The adapter.update predicate is keyed only on id, not on revoked IS NULL, so two concurrent requests presenting the same parent refresh token both pass the revocation check before either write completes — a classic TOCTOU race condition (CWE-367). Additionally, the schema lacked a UNIQUE constraint on oauthRefreshToken.token, so concurrent inserts did not collide on a database-level violation. The result is a forked refresh-token family from a single parent token, violating RFC 9700 §4.14's requirement for atomic family invalidation on detected reuse (CWE-294, CWE-613) (GitHub Advisory, Fix Commit).
Successful exploitation allows an attacker holding a single stolen refresh token to maintain indefinite unauthorized access by creating forked refresh-token families that survive any single revocation attempt — as long as the attacker holds at least one branch of the forked family. Legitimate users whose tokens have been forked do not trigger family invalidation when they refresh, because the attacker's branch has already swapped the parent row, effectively bypassing detection. The impact is high on both confidentiality and integrity (access to protected resources at the victim's authorization scope), with no availability impact (GitHub Advisory).
No public proof-of-concept exploit code has been reported, and there is no evidence of in-the-wild exploitation as of the time of disclosure (Github Advisory). The EPSS score is approximately 0.41% (Feedly data) to 0.24% (GitHub Advisory Database), placing it in a low exploitation probability tier. The vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. Exploitation requires the attacker to already possess a valid refresh token (low privileges required) and the ability to send concurrent HTTP requests, which is achievable via scripting or timing attacks against SPAs sharing tokens across tabs or mobile clients retrying after failures (GitHub Advisory).
offline_access scope.@better-auth/oauth-provider >= 1.6.0 and < 1.6.11 (or better-auth >= 1.4.8-beta.7 and < 1.6.0) and that the offline_access scope is in use, meaning refresh tokens are minted.curl with &, Python asyncio, or a browser with multiple tabs), simultaneously submit two or more POST /oauth2/token requests with grant_type=refresh_token and the same stolen refresh token value before either request's revocation write completes.revoked check and each receives a new, distinct refresh token — creating a forked family. The attacker retains one branch while the legitimate user may receive the other.refreshTokenExpiresAt (default 7 days), which resets with each successful rotation (GitHub Advisory, Fix Commit).POST /oauth2/token requests with grant_type=refresh_token and the same refresh_token value arriving within milliseconds of each other from the same or different IP addresses.refresh_token in response) for the same parent refresh token value within a very short time window; subsequent access token usage from unexpected IP addresses or user agents.oauthRefreshToken rows sharing the same parentId or originating from the same parent token, with different token values and close createdAt timestamps — indicating a forked family.invalid_grant unexpectedly, while access continues from another source — suggesting the legitimate user lost the race and the attacker holds the winning branch (GitHub Advisory).The primary fix is to upgrade to @better-auth/oauth-provider@1.6.11 or better-auth@1.6.0 (for embedded plugin users), which introduces an atomic compare-and-swap (UPDATE ... WHERE id = ? AND revoked IS NULL) on the parent refresh token row, ensuring only one concurrent rotation wins and the loser receives invalid_grant (v1.6.11 Release). Existing database installations should manually add the unique constraint: CREATE UNIQUE INDEX oauth_refresh_token_token_uniq ON "oauthRefreshToken" (token);. If immediate upgrade is not possible, partial mitigations include: configuring the database adapter for serializable isolation or row-level locking on oauthRefreshToken; setting a very short refreshTokenExpiresIn (e.g., 60 seconds) to limit attacker persistence; implementing client-side mutex for refresh token usage; or disabling offline_access scope entirely to prevent refresh token issuance (GitHub Advisory).
The vulnerability was reported by community researcher @chdanielmueller and fixed by the Better Auth maintainers in a coordinated disclosure (GitHub Advisory). The fix was included in the v1.6.11 release alongside several other security hardening changes, including fixes for magic-link race conditions, device authorization binding, and SSRF vulnerabilities in the SSO plugin (v1.6.11 Release). The vulnerability was noted in CISA's weekly vulnerability bulletin (SB26-201) and received coverage from automated vulnerability tracking services shortly after NVD publication.
Source: This report was generated using AI
Free Vulnerability Assessment
Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.
Get a personalized demo
"Best User Experience I have ever seen, provides full visibility to cloud workloads."
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
"We know that if Wiz identifies something as critical, it actually is."