CVE-2026-67333
better-auth before 1.6.13 Stored XSS via javascript redirect_uri
better-auth before 1.6.13 (and pre-release builds 1.7.0-beta.0 through 1.7.0-beta.3) fail to validate the scheme of redirect_uris registered via the deprecated oidc-provider plugin and the mcp plugin (which wraps the same provider). An attacker can register an OAuth client with a javascript: redirect_uri, which the authorization server later returns unchanged in the consent response. If the deployment's consent page navigates the browser to the returned redirectURI (e.g. assigning it to window.location.href), the attacker's JavaScript executes in the authorization-server origin, exposing the victim's session and enabling account takeover.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- Passive
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
5.1
better-auth before 1.6.13 Stored XSS via javascript redirect_uri
better-auth before 1.6.13 (and pre-release builds 1.7.0-beta.0 through 1.7.0-beta.3) fail to validate the scheme of redirect_uris registered via the deprecated oidc-provider plugin and the mcp plugin (which wraps the same provider). An attacker can register an OAuth client with a javascript: redirect_uri, which the authorization server later returns unchanged in the consent response. If the deployment's consent page navigates the browser to the returned redirectURI (e.g. assigning it to window.location.href), the attacker's JavaScript executes in the authorization-server origin, exposing the victim's session and enabling account takeover.
- Record
CVE-2026-67333- CVSS 4.0
- 5.1 Medium
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N - CVSS 3.1
- 7.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
EUVDEUVD-2026-51810
5.1
better-auth before 1.6.13 (and pre-release builds 1.7.0-beta.0 through 1.7.0-beta.3) fail to validate the scheme of redirect_uris registered via the deprecated oidc-provider plugin and the mcp plugin (which wraps the same provider). An attacker can register an OAuth client with a javascript: redirect_uri, which the authorization server later returns unchanged in the consent response. If the deployment's consent page navigates the browser to the returned redirectURI (e.g. assigning it to window.location.href), the attacker's JavaScript executes in the authorization-server origin, exposing the victim's session and enabling account takeover.
- Record
EUVD-2026-51810- CVSS 4.0
- 5.1 Medium
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-86j7-9j95-vpqj
7.7
Better Auth has stored XSS in the auth-server origin via javascript: redirect_uri in oidc-provider and mcp
Am I affected?
Check each condition. Users are affected when all of the first three hold.
- Their application enables the
oidc-providerplugin or themcpplugin frombetter-auth/plugins. Themcpplugin wraps the same provider and carries the same defect. Both are on the migration path to@better-auth/oauth-provider, which is not affected. - Their application
better-authversion is1.6.12or earlier on the stable line, or any1.7.0-betabuild on the pre-release line. Both release lines carry the same defect. - Their application consent page is a client component that reads
redirectURIfrom theauthClient.oauth2.consent(...)response and assigns it to a browser navigation target such aswindow.location.href,location.assign, orlocation.replace.
Two conditions raise an application's exposure:
- It sets
allowDynamicClientRegistration: true. Client registration is then unauthenticated, so any visitor can plant the malicious client. The default isfalse, which limits planting to authenticated users. - It exposes the consent page to ordinary end users rather than to a restricted operator audience.
A developer's application is not affected when any of these hold:
- Their application copied the project's
consent-buttons.tsxdemo verbatim. That file reads aurifield that this plugin never returns, so its navigation branch never runs and it falls through to an error toast. - Their application completse the consent flow with a server-side redirect, for example a Next.js or Remix server action. Browsers do not follow a
javascript:URL delivered in aLocationresponse header. - Their application uses
@better-auth/oauth-providerinstead of the deprecatedoidc-providerplugin.
Fix:
- Upgrade to
[email protected](stable) or1.7.0-beta.4(pre-release). - If developers cannot upgrade their applications, see the workarounds below.
Summary
The deprecated oidc-provider plugin registers OAuth clients without validating the scheme of their redirect_uris. An attacker stores a javascript: URI as a client redirect target, and the authorization server later returns that URI to the browser in the consent response. A consent page that navigates to the returned value then executes attacker JavaScript in the authorization-server origin, which exposes the victim's session and enables account takeover. The mcp plugin wraps the same provider and carries the same defect, so MCP server deployments are affected as well; like oidc-provider, it is migrating to @better-auth/oauth-provider.
Details
Client registration accepts any string. The registration body schema types redirect_uris as z.array(z.string()) with no scheme check, so POST /oauth2/register stores a value such as javascript:fetch('/api/auth/get-session')//. In the default configuration, allowDynamicClientRegistration is false, so registration requires an authenticated session; any logged-in user qualifies. With dynamic client registration enabled, registration is unauthenticated.
The dangerous value then survives the authorization-code flow unchanged. GET /oauth2/authorize matches the request redirect_uri against the stored list by exact string equality, so the registered javascript: URI matches itself and is written into the consent verification record. When the user approves on the consent screen, the handler runs new URL(value.redirectURI), appends the authorization code through searchParams.set, and returns the result in JSON under the key redirectURI. The javascript: scheme passes through new URL intact, and a trailing // in the payload comments out the appended query string.
The plugin documents the consent call but not the redirect step that follows it, and it gives no warning that redirectURI can carry a dangerous scheme. The natural way an operator completes the flow is to assign res.data.redirectURI to window.location.href. Per the URL specification and browser…
- Record
GHSA-86j7-9j95-vpqj- CVSS 3.1
- 7.7 High
CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N - Weakness
- CWE-79, CWE-601
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-w277-2xmj-j2rc
5.1
better-auth before 1.6.13 (and pre-release builds 1.7.0-beta.0 through 1.7.0-beta.3) fail to...
better-auth before 1.6.13 (and pre-release builds 1.7.0-beta.0 through 1.7.0-beta.3) fail to validate the scheme of redirect_uris registered via the deprecated oidc-provider plugin and the mcp plugin (which wraps the same provider). An attacker can register an OAuth client with a javascript: redirect_uri, which the authorization server later returns unchanged in the consent response. If the deployment's consent page navigates the browser to the returned redirectURI (e.g. assigning it to window.location.href), the attacker's JavaScript executes in the authorization-server origin, exposing the victim's session and enabling account takeover.
- Record
GHSA-w277-2xmj-j2rc- CVSS 4.0
- 5.1 Medium
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 7.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
NVD
5.1
better-auth before 1.6.13 (and pre-release builds 1.7.0-beta.0 through 1.7.0-beta.3) fail to validate the scheme of redirect_uris registered via the deprecated oidc-provider plugin and the mcp plugin (which wraps the same provider). An attacker can register an OAuth client with a javascript: redirect_uri, which the authorization server later returns unchanged in the consent response. If the deployment's consent page navigates the browser to the returned redirectURI (e.g. assigning it to window.location.href), the attacker's JavaScript executes in the authorization-server origin, exposing the victim's session and enabling account takeover.
- Record
CVE-2026-67333- CVSS 4.0
- 5.1 Medium
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 7.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
OSV
5.1
better-auth before 1.6.13 Stored XSS via javascript redirect_uri
better-auth before 1.6.13 (and pre-release builds 1.7.0-beta.0 through 1.7.0-beta.3) fail to validate the scheme of redirect_uris registered via the deprecated oidc-provider plugin and the mcp plugin (which wraps the same provider). An attacker can register an OAuth client with a javascript: redirect_uri, which the authorization server later returns unchanged in the consent response. If the deployment's consent page navigates the browser to the returned redirectURI (e.g. assigning it to window.location.href), the attacker's JavaScript executes in the authorization-server origin, exposing the victim's session and enabling account takeover.
- Record
CVE-2026-67333- CVSS 4.0
- 5.1 Medium
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N - Weakness
- CWE-79
- Updated
- 2026-11-02
OSVGHSA-86j7-9j95-vpqj
7.7
Better Auth has stored XSS in the auth-server origin via javascript: redirect_uri in oidc-provider and mcp
Am I affected?
Check each condition. Users are affected when all of the first three hold.
- Their application enables the
oidc-providerplugin or themcpplugin frombetter-auth/plugins. Themcpplugin wraps the same provider and carries the same defect. Both are on the migration path to@better-auth/oauth-provider, which is not affected. - Their application
better-authversion is1.6.12or earlier on the stable line, or any1.7.0-betabuild on the pre-release line. Both release lines carry the same defect. - Their application consent page is a client component that reads
redirectURIfrom theauthClient.oauth2.consent(...)response and assigns it to a browser navigation target such aswindow.location.href,location.assign, orlocation.replace.
Two conditions raise an application's exposure:
- It sets
allowDynamicClientRegistration: true. Client registration is then unauthenticated, so any visitor can plant the malicious client. The default isfalse, which limits planting to authenticated users. - It exposes the consent page to ordinary end users rather than to a restricted operator audience.
A developer's application is not affected when any of these hold:
- Their application copied the project's
consent-buttons.tsxdemo verbatim. That file reads aurifield that this plugin never returns, so its navigation branch never runs and it falls through to an error toast. - Their application completse the consent flow with a server-side redirect, for example a Next.js or Remix server action. Browsers do not follow a
javascript:URL delivered in aLocationresponse header. - Their application uses
@better-auth/oauth-providerinstead of the deprecatedoidc-providerplugin.
Fix:
- Upgrade to
[email protected](stable) or1.7.0-beta.4(pre-release). - If developers cannot upgrade their applications, see the workarounds below.
Summary
The deprecated oidc-provider plugin registers OAuth clients without validating the scheme of their redirect_uris. An attacker stores a javascript: URI as a client redirect target, and the authorization server later returns that URI to the browser in the consent response. A consent page that navigates to the returned value then executes attacker JavaScript in the authorization-server origin, which exposes the victim's session and enables account takeover. The mcp plugin wraps the same provider and carries the same defect, so MCP server deployments are affected as well; like oidc-provider, it is migrating to @better-auth/oauth-provider.
Details
Client registration accepts any string. The registration body schema types redirect_uris as z.array(z.string()) with no scheme check, so POST /oauth2/register stores a value such as javascript:fetch('/api/auth/get-session')//. In the default configuration, allowDynamicClientRegistration is false, so registration requires an authenticated session; any logged-in user qualifies. With dynamic client registration enabled, registration is unauthenticated.
The dangerous value then survives the authorization-code flow unchanged. GET /oauth2/authorize matches the request redirect_uri against the stored list by exact string equality, so the registered javascript: URI matches itself and is written into the consent verification record. When the user approves on the consent screen, the handler runs new URL(value.redirectURI), appends the authorization code through searchParams.set, and returns the result in JSON under the key redirectURI. The javascript: scheme passes through new URL intact, and a trailing // in the payload comments out the appended query string.
The plugin documents the consent call but not the redirect step that follows it, and it gives no warning that redirectURI can carry a dangerous scheme. The natural way an operator completes the flow is to assign res.data.redirectURI to window.location.href. Per the URL specification and browser…
- Record
GHSA-86j7-9j95-vpqj- CVSS 3.1
- 7.7 High
CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N - Weakness
- CWE-601, CWE-79
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
better-authnpm |
before 1.6.13 | 1.6.13 |
better-authnpm |
1.7.0-beta.0 up to 1.7.0-beta.4 | 1.7.0-beta.4 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-67333 is a medium vulnerability (CVSS 5.1) in Better-auth, published July 7, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.26%, the 18th percentile. Fixed in better-auth 1.6.13.
References
github.com/better-auth/better-auth/security/advisories/GHSA-86j7-9j95-vpqj
vulncheck.com/advisories/better-auth-before-stored-xss-via-javascript-redirect-uri
github.com/better-auth/better-auth/releases/tag/v1.6.13
github.com/better-auth/better-auth/releases/tag/v1.7.0-beta.4
github.com/advisories/GHSA-86j7-9j95-vpqj
nvd.nist.gov/vuln/detail/CVE-2026-67333
github.com/advisories/GHSA-w277-2xmj-j2rc
github.com/CVEProject/cvelistV5/tree/main/cves/2026/67xxx/CVE-2026-67333.json
github.com/better-auth/better-auth
Left out here: the rest of 2 source descriptions. The JSON record has them.