CVE-2026-53518: @better auth/oauth provider @better-auth/oauth-provider's OAuth Authorization-code Grant Allows Vulnerability
HIGHCVE-2026-53518 is a HIGH (CVSS 8.1) @better-auth/oauth-provider's oauth authorization-code grant allows vulnerability (CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')) affecting @better auth/oauth provider libraries in the npm ecosystem. The issue involves @better-auth/oauth-provider's oauth authorization-code grant allows concurrent redemption when two token requests race the find-then-delete primitive. Remediation is available by upgrading affected packages to version 1.6.11.
CVE-2026-53518 at a Glance
Security Impact
CVSS: 8.1
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N).
How to Fix CVE-2026-53518
To remediate this vulnerability, upgrade all affected @better auth/oauth provider dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
npm install @better-auth/oauth-provider@1.6.11
npm install better-auth@1.6.11
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
npm ls @better-auth/oauth-provider
How to Check if You Are Affected
To determine whether your Node.js application is affected by CVE-2026-53518, inspect your project dependencies using npm:
npm ls @better-auth/oauth-provider
Analyze the terminal output to locate any version of @better auth/oauth provider in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.6.11), your application is affected.
Note: The npm ls @better-auth/oauth-provider command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition'), where the product contains a concurrent code sequence that requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence operating concurrently. In @better auth/oauth provider, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-53518 Affected @better auth/oauth provider Versions
2 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
@better-auth/oauth-provider
|
npm |
≥ 1.6.0
< 1.6.11
|
1.6.11
|
|
better-auth
|
npm |
< 1.6.11
|
1.6.11
|
References
Frequently Asked Questions
What is CVE-2026-53518?
Which @better auth/oauth provider versions are affected?
What version fixes CVE-2026-53518?
Is @better-auth/oauth-provider affected?
Is better-auth affected?
What is the CVSS score of CVE-2026-53518?
What CWE is associated with CVE-2026-53518?
How can I check npm dependencies for CVE-2026-53518?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-7w99-5wm4-3g79",
"modified" : "2026-07-20T19:24:51Z",
"published" : "2026-07-07T20:56:35Z",
"aliases" : [ "CVE-2026-53518" ],
"summary" : "@better-auth/oauth-provider's OAuth authorization-code grant allows concurrent redemption when two token requests race the find-then-delete primitive",
"details" : "### Am I affected?\n\nUsers are affected if all of the following are true:\n\n- 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`, or enables the legacy `oidc-provider` or `mcp` plugins from `better-auth/plugins`.\n- Their application exposes `/api/auth/oauth2/token` (or the legacy plugins' `/oauth2/token` and `/mcp/token`) as a token endpoint to OAuth/OIDC clients, including internal MCP clients (Claude Desktop, custom MCP tool callers, AI agents).\n- 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.\n\nFix:\n\n1. Upgrade to `@better-auth/oauth-provider@1.6.11` or later. If developers use the legacy plugin paths from `better-auth/plugins`, upgrade `better-auth` to `1.6.11` or later.\n2. If developers cannot upgrade, see workarounds below.\n\n### Summary\n\nThe 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.\n\n### Details\n\nThe 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.\n\nThe 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.\n\n### Patches\n\nFixed 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`.\n\nError-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.\n\n### Workarounds\n\nNone of these close the bug fully without a code patch. Upgrading is the only good path.\n\n- **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 `code` parameter and serializes concurrent requests for the same code. Fragile under multi-instance deployments unless the registry is shared (Redis-backed).\n- **Database-layer**: add a SQL or Mongo uniqueness constraint that prevents two `oauthAccessToken` rows 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.\n- **Application-layer**: wrap `deleteVerificationByIdentifier` with a custom hook that uses `adapter.deleteMany` and surfaces the count, then injects an `invalid_grant` rejection when the count is zero. Requires forking the internal adapter.\n\n### Impact\n\n- **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.\n- **Detection bypass**: standard OAuth single-use enforcement does not fire for the second redemption when both requests interleave through the read step.\n- **Legacy-plugin reach**: `oidc-provider` and `mcp` plugins share the primitive on the same surface, so deployments using them inherit the same impact.\n\n### Credit\n\nReported by @chdanielmueller.\n\n### Resources\n\n- [CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization (Race Condition)](https://cwe.mitre.org/data/definitions/362.html)\n- [CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition](https://cwe.mitre.org/data/definitions/367.html)\n- [CWE-294: Authentication Bypass by Capture-replay](https://cwe.mitre.org/data/definitions/294.html)\n- [RFC 6749 §4.1.2: Authorization Response](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2)\n- [OAuth 2.1 §4.1: Authorization Code Grant](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1#section-4.1)",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N"
}, {
"type" : "CVSS_V4",
"score" : "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"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "npm",
"name" : "@better-auth/oauth-provider"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "1.6.0"
}, {
"fixed" : "1.6.11"
} ]
} ]
}, {
"package" : {
"ecosystem" : "npm",
"name" : "better-auth"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "1.6.11"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/better-auth/better-auth/security/advisories/GHSA-7w99-5wm4-3g79"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-53518"
}, {
"type" : "WEB",
"url" : "https://github.com/better-auth/better-auth/commit/b4bc65a007784b2eb0efb459e5fa6fd8055d3ec9"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/better-auth/better-auth"
}, {
"type" : "WEB",
"url" : "https://github.com/better-auth/better-auth/releases/tag/v1.6.11"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-294", "CWE-362", "CWE-367" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-07-07T20:56:35Z",
"nvd_published_at" : "2026-07-15T18:16:48Z"
}
}