Live › vulnerability › GHSA-r4xp-prcw-77qf
Go to dashboardThe OAuth Proxy plugin in affected better-auth releases trusts any user profile it can decrypt, and when the proxy secret matches the global Better Auth secret and sign-in state is stored in cookies, anyone can build a fake profile for a victim's email. The attacker then signs in as that user without an account or victim action.
Summary written from the sources below. Check the originals before acting.
First seen by InfraStack 2026-10-27 15:34 UTC. All times on this page are UTC.
Applications running from up to but not including that use the OAuth Proxy plugin with cookie-backed sign-in state and implicit account linking. The exposure depends on the proxy secret matching the global secret across environments, so teams using database or secondary storage for state, or a distinct proxy secret, are not exposed by this path.
better-auth1.5.0-beta.121.7.7| Product | Ecosystem | Affected | Fixed in |
|---|---|---|---|
| better-auth | npm | >= 1.5.0-beta.12, < 1.7.7 | 1.7.7 |
npm ls better-auth and confirm the installed version is below 1.7.7 and at least 1.5.0-beta.12.secret is unset or equal to the global Better Auth secret.account.storeStateStrategy is set to "cookie", and whether implicit account linking is enabled (the default).better-auth to 1.7.7 once released, across every node and environment in the proxy flow, including preview and development deployments.secret in every participating environment, or set account.storeStateStrategy: "database", or remove the OAuth Proxy plugin.Each row is the first time that source carried this signal. The analyst’s rows are its own findings.
You may be affected if you use better-auth from 1.5.0-beta.12 through versions before 1.7.7 with the OAuth Proxy plugin. You are affected only if all of these are also true:
secret, or its secret equals that environment's global Better Auth secret.account.storeStateStrategy: "cookie"). With a database or secondary storage, this is only the case if you chose it explicitly.You are not affected by this path if every participating environment uses a proxy secret distinct from its global Better Auth secret, if sign-in state is stored in the database, or if you use a version before 1.5.0-beta.12.
The OAuth Proxy plugin trusts any user profile it can decrypt. In the affected setup, Better Auth encrypts sign-in state, including data the caller chose, with the same secret and hands it to anyone who starts a social sign-in. An attacker can use this to get a fake profile for another user's email address that the proxy accepts as real.
An attacker without an account who knows a user's verified email address can sign in as that user, with that user's permissions. They can read private data, change the account, and link a provider account of their choice to it. They need no provider sign-in and no action from the victim. No availability impact is established, and a reported open redirect was not confirmed.
The fix is merged for the planned better-auth 1.7.7 release. That package is not available yet.
Upgrade all nodes handling the same cookie-backed OAuth or SAML state flow and all OAuth Proxy participants together, including the production coordinator and preview or development deployments. Keep installed Better Auth packages released alongside better-auth on the same release version. Restart pending sign-in and account-linking flows; pre-upgrade state cookies and proxy payloads are rejected. Public options and API signatures are unchanged.
Until you upgrade to the fixed release, apply one of these:
secret across every environment that takes part in the proxy flow, and keep it different from each environment's global Better Auth secret.account.storeStateStrategy: "database". This is already the default when a database or secondary storage is configured. If Magic Link is also enabled, switching can expose a separate cross-purpose verification-record path in affected releases. Ensure the two flows resolve to distinct stored identifiers; with built-in options, use Magic Link storeToken: "hashed" with global verification.storeIdentifier unset or "plain", or disable Magic Link or both built-in social and Generic OAuth sign-in.Setting account.accountLinking.disableImplicitLinking: true stops this path from taking over an existing account. It does not fix the underlying flaw: the callback can still accept attacker-made data as a provider identity. Apply one of the steps above as well.
This page as .md · .json · in your agent: get_signal("GHSA-r4xp-prcw-77qf")
GitHub Advisory Database, CC-BY 4.0. Posts quoted belong to their authors.