GHSA-392p-2q2v-4372: Better Auth: OAuth refresh-token rotation forks the token family on concurrent redemption
Am I affected?
Users are affected if all of the following are true:
- Their project depends on @better-auth/oauth-provider at a version >= 1.6.0, < 1.6.11, or uses the embedded plugin in better-auth >= 1.4.8-beta.7, < 1.6.0.
- At least one OAuth client served by their application's authorization server requests the offline_access scope, so refresh tokens are minted.
- Concurrent redemption of the same refresh token is reachable: an SPA shares one refresh token across browser tabs without a mutex, a mobile client retries after a transient failure, an attacker who has stolen a refresh token times two requests, or a service worker queues offline requests.
If developer applications do not request offline_access for any client, no refresh tokens are minted and they are not exposed.
Fix:
1. Upgrade to @better-auth/oauth-provider@1.6.11 or later.
2. If developers cannot upgrade, see workarounds below.
Summary
The OAuth provider's POST /oauth2/token endpoint, on the refresh_token grant, performs a non-atomic read / validate / revoke / mint sequence on the oauthRefreshToken row. Two concurrent requests presenting the same parent refresh token both pass the revocation check before either revoke completes, so each mints a fresh refresh token. The replay-detection branch only fires when revoked is already truthy at read time, which is exactly the state concurrent attackers race past. The result is a forked refresh-token family from a single parent token.
Details
The adapter.update predicate on the parent row is keyed on id only; it does not include revoked IS NULL, so two concurrent updates both succeed (last-write-wins, no error path). The schema does not declare unique on oauthRefreshToken.token, so concurrent creates do not collide on a unique-key violation either.
RFC 9700 §4.14 (OAuth Security Best Current Practice) prescribes refresh-token family invalidation on detected reuse; this implementation tries to enforce that contract through the revoked check, but the
Details
Original advisory: https://github.com/advisories/GHSA-392p-2q2v-4372
Referenced CVEs
| CVE | CSIRTS overview | External |
|---|---|---|
| CVE-2026-53517 | coverage & exploitation status | NVD · CVE.org |
More from GitHub Security Advisories
- criticalGHSA-g936-7jqj-mwv8: TSDProxy: Internal proxy auth token forwarded to backend services enables management API …2026-07-10
- highGHSA-fpg8-7664-jc5q: melange: Incomplete package integrity verification allows data section substitution2026-07-10
- mediumGHSA-48rx-c7pg-q66r: Excon does not redact additional sensitive/risky headers when following redirects2026-07-10
- highGHSA-h4g2-xfmw-q2c9: Clauster: Non-loopback deployments can serve the dashboard unauthenticated when auth.enab…2026-07-10
- mediumGHSA-rqq5-2gf9-4w4q: Secure Headers: CSP directive injection via sandbox, plugin_types, and report_to when giv…2026-07-10