CVE-2026-53516 Overview
CVE-2026-53516 is an authentication bypass vulnerability in Better Auth, a TypeScript authentication and authorization library. Versions prior to 1.6.11 contain a flaw in the OAuth callback auto-link gate within handleOAuthUserInfo. The library accepts implicit account linking when the OAuth provider asserts email_verified: true, without verifying that the local user record's emailVerified field is also true. An attacker who pre-registers a victim's email through /sign-up/email can bind the victim's OAuth identity to the attacker-controlled account. The same primitive affects the one-tap flow, and setting emailAndPassword.requireEmailVerification: true does not mitigate the link-time verification gap. The issue is classified under [CWE-287] Improper Authentication.
Critical Impact
An attacker can hijack a victim's OAuth identity by pre-registering their email, gaining persistent access to the victim's account through federated login.
Affected Products
- Better Auth versions prior to 1.6.11
- Applications using Better Auth OAuth callback flows
- Applications using the Better Auth one-tap plugin
Discovery Timeline
- 2026-07-15 - CVE-2026-53516 published to NVD
- 2026-07-15 - Last updated in NVD database
- Fix released in Better Auth v1.6.11 via GitHub Pull Request 9578
Technical Details for CVE-2026-53516
Vulnerability Analysis
Better Auth exposes an OAuth account-linking primitive that automatically associates an incoming federated identity with an existing local user when the email addresses match. The pre-patch logic in handleOAuthUserInfo gated implicit linking on the OAuth provider's email_verified claim alone. It did not require the local user row to also have a verified email.
This asymmetry breaks the identity assurance model. An attacker registers victim@example.com locally via /sign-up/email before the victim ever creates an account. When the victim later authenticates through an OAuth provider such as Google, Better Auth links the provider identity to the attacker's local row. The attacker then signs in with either credential and controls the resulting session.
The one-tap plugin contained the equivalent flaw. Enabling emailAndPassword.requireEmailVerification: true does not address the issue because that setting governs sign-in gating, not the link-time trust decision.
Root Cause
The root cause is a missing verification check on the local account side of the linking equation. The gate trusted the provider's assertion in isolation. Both sides of an implicit merge must be independently verified before two identities are joined.
Attack Vector
An unauthenticated remote attacker registers accounts using targeted victim email addresses. When a victim authenticates via a supported OAuth provider, Better Auth silently links the accounts and grants the attacker durable access.
// Security patch in packages/better-auth/src/oauth2/link-account.ts
// fix(oauth): block OAuth linking to unverified local accounts (#9578)
const isTrustedProvider =
opts.isTrustedProvider ||
c.context.trustedProviders.includes(account.providerId);
+ // FIXME(next-minor): drop `requireLocalEmailVerified` option and make
+ // the gate unconditional.
+ const requireLocalEmailVerified =
+ accountLinking?.requireLocalEmailVerified ?? true;
if (
(!isTrustedProvider && !userInfo.emailVerified) ||
+ (requireLocalEmailVerified && !dbUser.user.emailVerified) ||
accountLinking?.enabled === false ||
accountLinking?.disableImplicitLinking === true
) {
Source: GitHub Commit da7e50b
The patch adds a requireLocalEmailVerified check that defaults to true. Linking now fails when the local dbUser.user.emailVerified flag is false, closing the pre-registration primitive. The same fix is applied to the one-tap plugin at packages/better-auth/src/plugins/one-tap/index.ts.
Detection Methods for CVE-2026-53516
Indicators of Compromise
- Local user records created via /sign-up/email where emailVerified remains false but an OAuth account row was later linked.
- Multiple linked provider identities on a single user row where the earliest event is an unverified email sign-up followed by an OAuth callback.
- OAuth callback logs showing successful link operations against users whose local verification status was never confirmed.
Detection Strategies
- Query the account table for entries linked to user rows with emailVerified = false and correlate against OAuth callback timestamps.
- Review application logs for handleOAuthUserInfo link events preceding any local email verification event for the same user.
- Compare Better Auth version metadata across deployments and flag instances below 1.6.11.
Monitoring Recommendations
- Alert on any OAuth account link event where the target local user has emailVerified: false.
- Track spikes in /sign-up/email registrations for domains matching your customer base, which may indicate targeted pre-registration.
- Monitor for user records with multiple session origins (password and OAuth) established close in time to a link event.
How to Mitigate CVE-2026-53516
Immediate Actions Required
- Upgrade Better Auth to 1.6.11 or later across all applications and services.
- Audit existing user and account tables for links created against unverified local rows and force re-verification or unlink where suspicious.
- Invalidate active sessions for any user account showing signs of the pre-registration linking pattern.
Patch Information
The fix ships in Better Auth v1.6.11. The patch introduces a requireLocalEmailVerified option (default true) in both the OAuth callback and one-tap linking paths. See the GitHub Security Advisory GHSA-g38m-r43w-p2q7 and GitHub Release v1.6.11 for details.
Workarounds
- Set accountLinking.disableImplicitLinking: true to block all implicit OAuth linking until you can upgrade.
- Set accountLinking.enabled: false if your application does not require automatic account linking.
- Restrict /sign-up/email behind additional verification or rate limits to reduce the pre-registration attack surface.
# Configuration example - disable implicit linking as a pre-upgrade workaround
npm install better-auth@^1.6.11
# In your Better Auth server configuration:
# betterAuth({
# account: {
# accountLinking: {
# enabled: true,
# disableImplicitLinking: true,
# requireLocalEmailVerified: true,
# },
# },
# })
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

