better-auth before 1.7.7: an email is enough to take over an account
A critical better-auth flaw lets an attacker who knows a user's email open a session in their account when Magic Link and OAuth sign-in are both on. Fixed in 1.7.7, with interim config workarounds.

If your project uses better-auth with email sign-in links (Magic Link) and social sign-in or any OAuth provider, an attacker who knew a user's email could open a session in their account. Here you will find out whether your configuration is affected, and how to fix it today.
What is the better-auth flaw?
The flaw is that better-auth accepted an OAuth sign-in state value as if it were a Magic Link token. GitHub's advisory lists it as CVE-2026-114607 and rates it critical, 9.1 on CVSS 3.1.
The state is the value that ties the start of an OAuth sign-in to its callback. The Magic Link token is the one sent by email that opens the session. So the library accepted a value anyone can request in place of a token that should only reach the account owner's mailbox.
The original advisory was published in the better-auth repository on September 30, 2026, and the fix shipped in 1.7.7. On October 27, 2026 advisory GHSA-965c-763c-88jm was added to the GitHub Advisory Database after review.
How does an attacker get in with just an email?
The attacker needs no mailbox access, no OAuth provider sign-in and no OAuth callback. According to the advisory, the attack goes like this:
Start an OAuth sign-in for any email address they choose.
Take the state value that comes back.
Use it to complete a Magic Link sign-in for the same address, which gives a normal session with that account's permissions.
If Magic Link sign-up is enabled and no account exists for the address, the attacker can create a new account wrongly marked as email verified. The advisory says that false flag can also bypass the library's default protections for unproven accounts when the real owner signs in later.
Is my project affected?
Your project is affected if your version is from 1.4.0-beta.18 through versions before 1.7.7, and all three of these are true:
Magic Link is enabled with the default
storeToken: "plain", or withstoreToken: "hashed"and the globalverification.storeIdentifier: "hashed".At least one built-in social provider or a Generic OAuth provider is enabled.
OAuth state is stored in the database (
account.storeStateStrategy: "database"), which is the default when a database or secondary storage is configured.
In other words, a simple setup: a database, Magic Link and a social sign-in button. If forged tokens are on your mind, we covered the Postiz flaw that lets a user take over a whole organization.
How do you fix it?
Update better-auth to 1.7.7, together with its adapters, plugins and integrations. The release notes say the version fixed a critical Magic Link account-takeover vulnerability.
Mind these points from the advisory before you deploy:
If several servers share the same verification storage, upgrade them all in the same cutover.
Magic Links and OAuth or SAML states created before the upgrade cannot complete, so users request new ones.
If you have custom
verification.storeIdentifier.overridesrules, update them to match themagic-link:andauth-state:prefixes.No user or account data migration is needed.
If your project is built on Next.js, also see the Next.js security update we covered if you have not updated yet.
What if you can't update now?
The advisory gives three interim workarounds until you upgrade:
Keep the state in a cookie instead of the database. If you use OAuth Proxy, first set a dedicated OAuth Proxy secret across all environments, different from each environment's global secret.
Set the Magic Link plugin's
storeTokento"hashed", and leave the globalverification.storeIdentifierunset or"plain".Disable Magic Link sign-in, or disable social and Generic OAuth sign-in.
export const auth = betterAuth({
account: {
storeStateStrategy: "cookie",
},
});Setting disableSignUp: true on the Magic Link plugin is not enough: it only blocks new accounts, not the takeover of an existing one.
Where do you start now?
Start with your version and configuration, since they decide whether your project is exposed at all.
Run
npm ls better-authand check your version.Open your
betterAuthconfiguration and check the three conditions above.Update to 1.7.7 with all plugins, or apply a workaround today and update later.
Tell your users that old sign-in links no longer work.
If you want someone to test your platform's sign-in flow the way an attacker would, that is the job of Muhassan.
All our app security articles are in one place: app security.
FAQ
Does the attacker need access to the victim's mailbox?
No. According to the advisory, knowing the email address is enough. The attacker needs no mailbox access, no OAuth provider sign-in and no OAuth callback.
If I set disableSignUp, am I safe?
No. The advisory says disableSignUp only blocks new verified accounts. It does not stop the takeover of existing accounts.
What happens to old Magic Links after the update?
Magic Links and OAuth or SAML states created before the upgrade cannot complete, so users request new ones. No user or account data migration is needed.
Which versions are affected?
From 1.4.0-beta.18 through versions before 1.7.7. Version 1.7.7 has the fix.


