CVE-2026-53517 Overview
CVE-2026-53517 is a race condition vulnerability in Better Auth, an authentication and authorization library for TypeScript. The flaw exists in the @better-auth/oauth-provider package, specifically in the POST /oauth2/token endpoint when handling the refresh_token grant. The endpoint performs a non-atomic read, validate, revoke, and mint sequence on the oauthRefreshToken row. Concurrent requests using the same parent refresh token can pass the revoked check simultaneously, creating forked refresh-token families. The issue affects versions from 1.4.8-beta.7 until 1.6.11, including embedded better-auth plugin versions before 1.6.0. This vulnerability is classified under [CWE-362] Concurrent Execution using Shared Resource with Improper Synchronization.
Critical Impact
Attackers with a valid refresh token can bypass refresh-token rotation controls, producing multiple concurrent token families and undermining OAuth session revocation guarantees.
Affected Products
- Better Auth @better-auth/oauth-provider from version 1.4.8-beta.7 up to (but not including) 1.6.11
- Embedded better-auth plugin versions before 1.6.0
- TypeScript applications integrating Better Auth OAuth2 token endpoints
Discovery Timeline
- 2026-07-15 - CVE-2026-53517 published to NVD
- 2026-07-15 - Last updated in NVD database
Technical Details for CVE-2026-53517
Vulnerability Analysis
The vulnerability stems from a Time-of-Check Time-of-Use (TOCTOU) race condition in the OAuth2 token refresh flow. When a client submits a refresh_token grant to POST /oauth2/token, the server reads the oauthRefreshToken row, validates that it has not been revoked, revokes it, and then mints a new refresh token. These four operations are not performed atomically. Attackers can send concurrent refresh requests using the same parent token before the revoke step completes, allowing multiple requests to pass validation. Each request then mints a new refresh-token family, forking the token lineage. The result breaks the invariant that refresh tokens follow a single rotation chain, weakening detection of token theft and session revocation.
Root Cause
The root cause is the absence of atomic conditional update semantics in the refresh-token rotation code path. The database read and subsequent state mutation should have been executed as a single compare-and-swap (CAS) or transactional operation with row-level locking. Instead, the sequential logic permits interleaving between concurrent requests sharing the same refresh token.
Attack Vector
An authenticated attacker holding a valid refresh token can exploit this issue over the network by issuing multiple simultaneous requests to the token endpoint. No user interaction is required. Successful exploitation produces multiple valid refresh-token families derived from a single parent, defeating rotation-based reuse detection.
// Security patch in packages/oauth-provider/src/revoke.ts
import { verifyJwsAccessToken } from "better-auth/oauth2";
import { APIError } from "better-call";
import type { JSONWebKeySet } from "jose";
-import { decodeRefreshToken } from "./token";
+import { decodeRefreshToken, invalidateRefreshFamily } from "./token";
import type {
OAuthOpaqueAccessToken,
OAuthOptions,
Source: Better Auth commit c6918ec
The patch introduces invalidateRefreshFamily to enforce family-wide invalidation when reuse or forking is detected. A companion memory-adapter change adds SQL-like IS NULL semantics to support CAS-style predicates:
// Security patch in packages/memory-adapter/src/memory-adapter.ts
+// Treat undefined and null as equivalent for `eq null`
+// predicates. Rows created without a nullable field
+// (the adapter factory's `transformInput` skips
+// `undefined`) store the field as `undefined`; a
+// CAS-style `WHERE field IS NULL` predicate from
+// caller code must match those rows, mirroring SQL
+// `IS NULL` and Mongo's missing-or-null semantics.
+if (value === null) {
+ return record[field] == null;
+}
+return record[field] === value;
Source: Better Auth commit c6918ec
Detection Methods for CVE-2026-53517
Indicators of Compromise
- Multiple valid refresh tokens issued in close succession from the same parent oauthRefreshToken row
- Concurrent POST /oauth2/token requests with identical refresh_token grant values
- Access tokens issued to the same subject from divergent refresh-token families within a short time window
- Sessions persisting after an expected rotation-based revocation event
Detection Strategies
- Instrument the OAuth2 token endpoint to log the parent refresh-token identifier, request timestamp, and originating client for each rotation event
- Alert on any parent refresh-token ID that produces more than one successful rotation within a narrow time window (for example, under 500 milliseconds)
- Correlate access-token issuance events by subject and client to identify divergent token lineages that should not coexist
Monitoring Recommendations
- Ingest OAuth provider logs into a centralized analytics platform and normalize token_id, parent_token_id, and client_id fields for correlation
- Monitor for anomalous burst patterns of refresh_token grant requests originating from a single IP or client credential
- Track database write conflicts and retry rates on the oauthRefreshToken table as an early indicator of concurrent rotation attempts
How to Mitigate CVE-2026-53517
Immediate Actions Required
- Upgrade @better-auth/oauth-provider and any embedded better-auth plugins to version 1.6.11 or later without delay
- Invalidate all currently active refresh tokens after upgrading to force clients to complete a clean re-authentication flow
- Audit issued refresh tokens for evidence of forked families and revoke any suspected duplicates using the newly available invalidateRefreshFamily primitive
Patch Information
The issue is fixed in Better Auth version 1.6.11. The fix introduces atomic refresh-token family invalidation and updates the memory adapter to correctly evaluate CAS-style WHERE field IS NULL predicates. Review the GitHub Security Advisory GHSA-392p-2q2v-4372 and the v1.6.11 release notes for complete details.
Workarounds
- If an immediate upgrade is not feasible, place the token endpoint behind a per-refresh-token mutex or distributed lock so only one rotation request per parent token proceeds at a time
- Reduce refresh-token lifetime and increase re-authentication frequency to shrink the exploitation window
- Rate-limit POST /oauth2/token refresh_token grant requests per client to prevent concurrent-request bursts
# Update Better Auth OAuth provider to the fixed version
npm install @better-auth/oauth-provider@1.6.11
npm install better-auth@latest
# Verify installed versions
npm ls @better-auth/oauth-provider better-auth
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

