CVE-2026-53512

CVE-2026-53512 is a critical-severity improper authentication vulnerability in better-auth (npm), affecting versions < 1.6.11. It is fixed in 1.6.11.

Summary

Better Auth: OAuth refresh-token replay via missing client authentication on oidc-provider and mcp plugins

Full technical description

Am I affected?

Users are affected if all of the following are true:

  • Their application uses better-auth and has enabled at least one of: oidcProvider() (imported from better-auth/plugins/oidc-provider), or mcp() (imported from better-auth/plugins/mcp).
  • Their application has at least one confidential OAuth client registered (any client with type: "web" | "native" | "user-agent-based" in the oauthApplication table, or any trustedClients entry without type: "public"). Public clients with PKCE are not affected.
  • Their application uses better-auth at a version below the patched release.

If an application only uses @better-auth/oauth-provider (the canonical replacement for oidc-provider) and the mcp plugin is not enabled, it is not affected.

Fix:

  1. Upgrade to [email protected] or later.
  2. Migrate from the deprecated oidcProvider() to @better-auth/oauth-provider when feasible. The new package enforces client authentication on both grants by default.
  3. If developers cannot upgrade their applications, see workarounds below.

The legacy oidcProvider and mcp plugins each expose an OAuth 2.0 token endpoint whose refresh_token grant authenticates the request entirely on possession of the bound refreshToken row and a matching client_id. Neither plugin verifies the registered confidential client's client_secret on the refresh path. An attacker who obtains any valid refresh_token (via database read, log capture, browser-side XSS, or CORS-amplified script in the mcp case) and the public client_id can mint fresh access tokens and rotated refresh tokens until the chain is revoked.

Details

RFC 6749 §6 and OAuth 2.1 §4.3 require confidential clients to authenticate to the token endpoint on every grant, including refresh. The same plugins' authorization_code grant correctly enforces client_secret (the oidc-provider via verifyStoredClientSecret, the mcp plugin via raw equality), which proves the omission on the refresh path is a regression rather than a design choice.

Token rotation issues a new refresh_token with each call, so a single leaked refresh-token grants indefinite access until the row is revoked or its refreshTokenExpiresAt (default 7 days) passes; rotation refreshes that window each call.

Two adjacent issues on the mcp surface ship in the same patch. The mcp authorization_code grant uses raw === for client-secret comparison and ignores the storeClientSecret: "encrypted" | "hashed" configuration; the fix routes both grants through verifyStoredClientSecret. The mcp /mcp/token endpoint sets Access-Control-Allow-Origin: * unconditionally, which amplifies the refresh bypass in browser contexts; the fix narrows the CORS allowlist.

The newer @better-auth/oauth-provider package routes both grants through validateClientCredentials and is not affected.

Workarounds

None of these close the bug fully without a code patch.

  • Migrate to @better-auth/oauth-provider if your deployment can adopt the new plugin. It enforces client_secret on both grants.
  • Force all clients to public + PKCE: set every client's type: "public" and require PKCE. The bug is unreachable when there is no client_secret to verify.
  • Network-layer ingress restriction: limit /api/auth/oauth2/token and /api/auth/mcp/token to known client IPs at the load balancer. Practical for server-to-server flows, not for end-user-device clients.
  • Out-of-band refresh-token rotation: on any suspicion of leak, run db.deleteMany({ model: "oauthAccessToken", where: [{ field: "clientId", value: <id> }] }) to invalidate all refresh tokens for the affected client.
  • For the mcp endpoint specifically: drop the wildcard CORS at an upstream proxy and replace with a tight allowlist.

Credit

Reported by @subhanUmer.

Resources

Impact

  • Indefinite confidential-client impersonation: an attacker holding any valid refresh_token and the public client_id can mint access tokens and rotated refresh tokens indefinitely, until the row is revoked. Rotation refreshes the expiration window each call.
  • Resource access at the user's authorized scope: every minted access token carries the original user's authorization scope, so the attacker reads or writes whatever the resource server grants for that scope.

The application does not adequately verify the identity of a user, device, or process before granting access. Typical impact: unauthorized access to functions or data reserved for authenticated parties.

CVE-2026-53512 has a CVSS score of 9.1 (Critical). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (1.6.11); upgrading removes the vulnerable code path.

Affected versions

better-auth (< 1.6.11)

Security releases

better-auth → 1.6.11 (npm)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

Already deployed Kodem?

See it in your environmentNew to Kodem? Get a demo →

Remediation advice

Fixed in [email protected]. The legacy oidcProvider and mcp token endpoints now require client_secret on the refresh_token grant for confidential clients, using the same constant-time comparison the authorization_code grant already used. Public clients are unaffected (they have no secret to enforce, and PKCE substitutes on the auth-code grant).

The Authorization: Basic parser is fixed to follow RFC 6749 §2.3.1: the credential is split on the first colon and each half is percent-decoded. Client IDs and secrets that contain reserved characters now authenticate correctly. The /mcp/token endpoint's CORS configuration is narrowed in the same change (the wildcard Access-Control-Allow-Origin: * header is removed), matching the standalone @better-auth/oauth-provider package.

The deprecated oidc-provider plugin remains deprecated. The recommended migration path is @better-auth/oauth-provider.

Frequently Asked Questions

  1. What is CVE-2026-53512? CVE-2026-53512 is a critical-severity improper authentication vulnerability in better-auth (npm), affecting versions < 1.6.11. It is fixed in 1.6.11. The application does not adequately verify the identity of a user, device, or process before granting access.
  2. How severe is CVE-2026-53512? CVE-2026-53512 has a CVSS score of 9.1 (Critical). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
  3. Which versions of better-auth are affected by CVE-2026-53512? better-auth (npm) versions < 1.6.11 is affected.
  4. Is there a fix for CVE-2026-53512? Yes. CVE-2026-53512 is fixed in 1.6.11. Upgrade to this version or later.
  5. Is CVE-2026-53512 exploitable, and should I be worried? Whether CVE-2026-53512 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  6. What actually determines whether CVE-2026-53512 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  7. How do I fix CVE-2026-53512? Upgrade better-auth to 1.6.11 or later.

Other vulnerabilities in better-auth

Stop the waste.
Protect your environment with Kodem.