Severity by source
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Network token endpoint (AV:N), but success needs winning a concurrency race (AC:H) and a user-generated code (UI:R); no client auth barrier (PR:N); duplicate scoped credentials give C:H/I:H, no availability impact.
Primary rating from Vendor (https://github.com/better-auth/better-auth).
CVSS VectorVendor: https://github.com/better-auth/better-auth
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Lifecycle Timeline
6Blast Radius
ecosystem impact- 26 npm packages depend on better-auth (19 direct, 7 indirect)
Ecosystem-wide dependent count for version 1.6.11.
DescriptionCVE.org
Am I affected?
Users are affected if all of the following are true:
- Their project depends on
@better-auth/oauth-providerat a version>= 1.6.0, < 1.6.11, or uses the embedded plugin inbetter-auth >= 1.4.8-beta.7, < 1.6.0, or enables the legacyoidc-providerormcpplugins frombetter-auth/plugins. - Their application exposes
/api/auth/oauth2/token(or the legacy plugins'/oauth2/tokenand/mcp/token) as a token endpoint to OAuth/OIDC clients, including internal MCP clients (Claude Desktop, custom MCP tool callers, AI agents). - Their application has not implemented an external mitigation: a load-balancer-level idempotency cache keyed by
code, a database trigger that rejects duplicate token issuance for the same authorization code, or a custom adapter override that performs an atomic compare-and-delete.
Fix:
- Upgrade to
@better-auth/oauth-provider@1.6.11or later. If developers use the legacy plugin paths frombetter-auth/plugins, upgradebetter-authto1.6.11or later. - If developers cannot upgrade, see workarounds below.
Summary
The OAuth provider's POST /oauth2/token endpoint, on the authorization_code grant, redeems a single-use authorization code through a non-atomic find-then-delete sequence. Two concurrent requests with the same code value both pass the read step before either delete completes, then both proceed to PKCE verification and createUserTokens. Each surviving request mints a fresh access token, refresh token, and id token. RFC 6749 §4.1.2 requires authorization codes to be single-use; this primitive does not enforce that under concurrency.
Details
The same architectural primitive (find a single-use verification row, then delete it, then trust the row to authorize) is used in 20 other call sites across the codebase. The deletion primitive returns Promise<void>, discarding the row count surfaced by adapter.deleteMany, so no call site can detect "another caller already claimed this row". The fix lands at the primitive layer rather than at any individual call site.
The fix introduces a claimVerificationByIdentifier primitive at the internal-adapter layer that performs an atomic claim-and-return, replaces the find-then-delete pair at this call site, and migrates the highest-impact variant sites in the same release.
Patches
Fixed in @better-auth/oauth-provider@1.6.11 and better-auth@1.6.11 for the legacy oidc-provider and mcp plugin paths. All three token-exchange call sites now consume the verification row through internalAdapter.consumeVerificationValue, an atomic claim primitive that deletes the row and returns its prior value in one operation. The first request to arrive takes the row and mints tokens; concurrent racers observe an empty result and return invalid_grant.
Error-code consistency is also tightened on the @better-auth/oauth-provider token endpoint: the malformed-verification-value branches previously returned a project-specific invalid_verification code, which is not part of RFC 6749 §5.2's response error set. Both branches now return invalid_grant so spec-compliant clients can branch on the standard code without a special case.
Workarounds
None of these close the bug fully without a code patch. Upgrading is the only good path.
- Network-layer: deploy an authorization-server-aware reverse proxy (Envoy, NGINX with Lua, custom Cloudflare Worker) that holds an in-flight registry keyed by the
codeparameter and serializes concurrent requests for the same code. Fragile under multi-instance deployments unless the registry is shared (Redis-backed). - Database-layer: add a SQL or Mongo uniqueness constraint that prevents two
oauthAccessTokenrows from being created with the same upstream code reference. Adapter-specific and not always feasible since the schema does not currently store the source code. - Application-layer: wrap
deleteVerificationByIdentifierwith a custom hook that usesadapter.deleteManyand surfaces the count, then injects aninvalid_grantrejection when the count is zero. Requires forking the internal adapter.
Impact
- Multiple independent token sets from a single authorization: forked access tokens, refresh tokens, and id tokens issued from the same code, all valid for the original user's authorization scope.
- Detection bypass: standard OAuth single-use enforcement does not fire for the second redemption when both requests interleave through the read step.
- Legacy-plugin reach:
oidc-providerandmcpplugins share the primitive on the same surface, so deployments using them inherit the same impact.
Credit
Reported by @chdanielmueller.
Resources
AnalysisAI
Single-use authorization-code enforcement can be bypassed under concurrency in the better-auth OAuth provider (@better-auth/oauth-provider 1.6.0 through 1.6.10, the embedded plugin in better-auth 1.4.8-beta.7 through 1.6.10, and the legacy oidc-provider and mcp plugins). Because the POST /oauth2/token authorization_code grant redeems the code via a non-atomic find-then-delete, two concurrent requests carrying the same code both pass the read step and each mint a fresh access, refresh, and id token for the original user's scope. …
Unlock full vulnerability intelligence
- Risk assessment & exploitation conditions
- Attack chain visualization
- Remediation with exact patch versions
- Threat intelligence from 22 sources
- Personal watchlist & email alerts
Free forever · No credit card required
Recommended ActionAI
Within 24 hours, inventory systems running better-auth versions 1.4.8-beta.7 through 1.6.10 and establish a patching plan; as interim mitigation, restrict network access to OAuth token endpoints to authorized callers only. …
Sign in for detailed remediation steps and compensating controls.
Threat intelligence, references, and detailed analysis are available after sign-in.
LiteSpeed User-End cPanel Plugin before 2.4.5 allows privilege escalation (possibly to root), as exploited in the wild i
UAF in Redis 8.2.1 via crafted Lua scripts by authenticated users. EPSS 12.4%. Patch available.
It was discovered, that redis, a persistent key-value database, due to a packaging issue, is prone to a (Debian-specific
Memory Corruption was discovered in the cmsgpack library in the Lua subsystem in Redis before 3.2.12, 4.x before 4.0.10,
Redis is an open source, in-memory database that persists on disk. Versions 8.2.1 and below allow an authenticated user
Redis before 2.8.21 and 3.x before 3.0.2 allows remote attackers to execute arbitrary Lua bytecode via the eval command.
A buffer overflow in Redis 3.2.x prior to 3.2.4 causes arbitrary code execution when a crafted command is sent. Rated cr
Code injection in OneUptime monitoring via custom JS monitor using vm module. PoC and patch available.
In applications using jfinal 4.9.08 and below, there is a deserialization vulnerability when using redis,may be vulnerab
An issue was found in Apache Airflow versions 1.10.10 and below. Rated critical severity (CVSS 9.8), this vulnerability
An Integer Overflow issue was discovered in the struct library in the Lua subsystem in Redis before 3.2.12, 4.x before 4
goanother Another Redis Desktop Manager =<1.6.1 is vulnerable to Cross Site Scripting (XSS) via src/components/Setting.v
Same weakness CWE-294 – Authentication Bypass by Capture-replay
View allSame technique Authentication Bypass
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-44734
GHSA-7w99-5wm4-3g79