BETTER-AUTH · GHSA-2f9c-7xj7-gh55 · Package
FIX → 1.8.0-beta.5 +1
The emailOTP() plugin in better-auth can be made to count concurrent guesses as one attempt, letting an attacker exceed allowedAttempts and sign in or reset a password. Email change codes could also be used on a different account, and on databases that ignore accents, a reset code could go to a different address.
first public Nov 3, 2026 · 1 source
Could this affect your app?
Free first check from your website. Connect your repo for the full answer.
Applications that use the emailOTP() plugin from better-auth 1.3.7 or later are exposed to the attempt-limit race. Email change codes apply only if changeEmail.enabled is true (from 1.5.0), and the accented-address issue applies only on databases whose collation ignores accents, common on MySQL. Apps that do not use emailOTP() can skip it.
Not affected if changeemail-disabled, no-emailotp-plugin, non-accent-insensitive-db
Who cares authentication, better-auth, email-otp, node
better-auth version with npm ls better-auth.emailOTP( in your auth config and check whether changeEmail.enabled is true.You are affected if you use the emailOTP() plugin from better-auth 1.3.7 or later. Each problem below adds its own condition:
changeEmail.enabled: true in the plugin, from 1.5.0.Attempt limit. Guesses that arrive at the same time could be counted as one attempt, so an attacker could make more guesses than allowedAttempts allows.
Email change codes. Codes for changing an email address were stored under a key built from both addresses. Two different address pairs could produce the same key, so a code requested from one account could be used from another.
Accented addresses. On databases that ignore accents, a lookup for an address could return an account with a different stored address. Password reset then sent the code to the requested address, not the account's own.
With the attempt limit problem, an unauthenticated attacker can make extra guesses against an active OTP and, if a guess hits, sign in or reset the password.
With the email change problem, a signed-in user can mark an unused address on their own account as verified. The real owner of that address may later be signed in to the attacker's account.
Check it with your coding agent
It reads this page and tells you if your code is affected.
Are you affected?
Ask from here. InfraStack checks the affected versions against your stack and answers in your inbox.
InfraStack checks the affected versions against your stack and answers in Slack, with the evidence and the fix.
Upgrade to 1.8.0-beta.5 +1
better-auth 1.7.16 on the 1.7 linebetter-auth 1.8.0-beta.5 on the 1.8 beta lineWith the accented address problem, an attacker who receives mail at an address that differs from the victim's only by accents can reset the victim's password, with no action from the victim.
Upgrade better-auth to 1.7.16, or to 1.8.0-beta.5 on the beta line. Email change codes sent before the upgrade must be requested again.
Turn off email change in the email OTP plugin, which is the default, and use the core email change flow instead. Lowering allowedAttempts and the OTP lifetime reduces the attempt limit problem but does not fix it.
The attempt counter was read and written in separate steps, so concurrent checks could each see the same count. Every guess now counts against the limit, and a correct check still leaves the OTP usable for the follow-up call. Email change codes are now bound to the requesting account and the new address. Looking up a user by email now returns an account only when its stored address matches the requested one, ignoring case, and the reset routes send the code to the address on the account.
The accented address problem was discovered by Anthropic's OSS Scanner, as vulnerability ANT-2026-Y7X5RTID.