CVE-2026-53513
Better Auth: Server-side request forgery via unvalidated OIDC endpoints on @better-auth/sso provider registration
Better Auth is an authentication and authorization library for TypeScript. Prior to 1.6.11, the @better-auth/sso plugin's POST /sso/register and POST /sso/update-provider endpoints accept attacker-controlled oidcConfig.userInfoEndpoint, tokenEndpoint, and jwksEndpoint URLs when skipDiscovery: true is set, store them on the ssoProvider row without origin validation, and fetch them during OIDC callback, allowing non-blind server-side request forgery and possible account linking when trustEmailVerified: true is configured. This issue is fixed in version 1.6.11.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
9.6
Better Auth: Server-side request forgery via unvalidated OIDC endpoints on @better-auth/sso provider registration
Better Auth is an authentication and authorization library for TypeScript. Prior to 1.6.11, the @better-auth/sso plugin's POST /sso/register and POST /sso/update-provider endpoints accept attacker-controlled oidcConfig.userInfoEndpoint, tokenEndpoint, and jwksEndpoint URLs when skipDiscovery: true is set, store them on the ssoProvider row without origin validation, and fetch them during OIDC callback, allowing non-blind server-side request forgery and possible account linking when trustEmailVerified: true is configured. This issue is fixed in version 1.6.11.
- Record
CVE-2026-53513- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-20, CWE-345, CWE-441, CWE-918
- Updated
- 2026-11-02
EUVDEUVD-2026-44733
9.6
Better Auth is an authentication and authorization library for TypeScript. Prior to 1.6.11, the @better-auth/sso plugin's POST /sso/register and POST /sso/update-provider endpoints accept attacker-controlled oidcConfig.userInfoEndpoint, tokenEndpoint, and jwksEndpoint URLs when skipDiscovery: true is set, store them on the ssoProvider row without origin validation, and fetch them during OIDC callback, allowing non-blind server-side request forgery and possible account linking when trustEmailVerified: true is configured. This issue is fixed in version 1.6.11.
- Record
EUVD-2026-44733- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-5rr4-8452-hf4v
9.6
@better-auth/sso provider registration has server-side request forgery via unvalidated OIDC endpoints
Am I affected?
Users are affected if all of the following are true:
- Their application uses
@better-auth/ssoat a version>= 0.1.0, < 1.6.11on the stable line, or any1.7.0-beta.xon the pre-release line. - The
sso()plugin is added to their application'sbetterAuth({ plugins: [...] })array. - Any user with a valid Better Auth session can reach
POST /sso/register(the plugin's default gate accepts any session).
For the non-blind SSRF impact (full IAM credential or internal HTTP body exfiltration), no further configuration is required.
For the account takeover escalation, additionally:
- Developers set
sso({ trustEmailVerified: true, ... }). - The developer's application deployment has accounts whose
emailoverlaps with attacker-chosen domains.
If developers do not enable the SSO plugin, their application is not affected.
Fix:
- Upgrade to
@better-auth/[email protected]or later. - If developers cannot upgrade, see workarounds below.
Summary
The @better-auth/sso plugin's POST /sso/register endpoint accepts attacker-controlled oidcConfig.userInfoEndpoint, tokenEndpoint, and jwksEndpoint URLs when skipDiscovery: true is set, persists them on the ssoProvider row without origin validation, then issues server-side fetches to those URLs during the OIDC callback. The fetched response body is reflected through the user profile, producing a non-blind SSRF reachable by any authenticated session. The same primitive exists on POST /sso/update-provider.
Details
The schema field types accept bare strings: no .url() validator, no origin gate. The discovery branch (skipDiscovery: false) routes URLs through validateDiscoveryUrl; the skip-discovery branch persists them as-is. At callback time three fetch sites read the stored URLs: validateAuthorizationCode for the token endpoint, betterFetch for the userInfo endpoint, and validateToken for the JWKS endpoint.
When trustEmailVerified: true is configured, the attacker can escalate to account linking. A malicious userInfo response with emailVerified: true and a chosen email triggers OAuth auto-link against any pre-existing user row with that email, compounding the SSRF into account takeover.
Patches
Fixed in @better-auth/[email protected]. Provider registration (POST /sso/register with skipDiscovery: true) and every POST /sso/update-provider request now validate each supplied OIDC endpoint URL (authorizationEndpoint, tokenEndpoint, userInfoEndpoint, jwksEndpoint, discoveryEndpoint) at registration time. A URL is rejected unless it satisfies one of two conditions:
- Its host is publicly routable on the internet, evaluated through the
@better-auth/core/utils/host.isPublicRoutableHostgate. RFC 1918 private ranges, RFC 4193 unique-local addresses, link-local addresses (including the cloud-metadata IP169.254.169.254), loopback, multicast, broadcast, and reserved ranges are rejected, along with cloud-metadata FQDNs. - Its origin is already listed in the application's
trustedOriginsconfiguration. This preserves the documented escape hatch for customers running internal IdPs intentionally on private networks.
The schema also tightens from z.string() to z.url() on those fields, so malformed URLs fail at parse time rather than at fetch time. Deployments running internal IdPs that previously worked must add the IdP's origin to trustedOrigins to keep working after upgrade.
Workarounds
If developers cannot upgrade immediately:
- Disable provider self-registration: set
sso({ providersLimit: 0 }). The limit is enforced before the schema branch, blocking every/sso/registerregardless ofskipDiscovery. - Reverse-proxy gate: block
POST /sso/registerandPOST /sso/update-providerat the edge, or restrict to a denylist of source IPs and a small admin user list. - Network-level egress controls: block egress from the auth server to RFC 1918, RFC 4193, link-local ranges…
- Record
GHSA-5rr4-8452-hf4v- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-20, CWE-345, CWE-441, CWE-918
- Updated
- 2026-11-02
NVD
9.6
Better Auth is an authentication and authorization library for TypeScript. Prior to 1.6.11, the @better-auth/sso plugin's POST /sso/register and POST /sso/update-provider endpoints accept attacker-controlled oidcConfig.userInfoEndpoint, tokenEndpoint, and jwksEndpoint URLs when skipDiscovery: true is set, store them on the ssoProvider row without origin validation, and fetch them during OIDC callback, allowing non-blind server-side request forgery and possible account linking when trustEmailVerified: true is configured. This issue is fixed in version 1.6.11.
- Record
CVE-2026-53513- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-20, CWE-345, CWE-441, CWE-918
- Updated
- 2026-11-02
OSV
9.6
Better Auth: Server-side request forgery via unvalidated OIDC endpoints on @better-auth/sso provider registration
Better Auth is an authentication and authorization library for TypeScript. Prior to 1.6.11, the @better-auth/sso plugin's POST /sso/register and POST /sso/update-provider endpoints accept attacker-controlled oidcConfig.userInfoEndpoint, tokenEndpoint, and jwksEndpoint URLs when skipDiscovery: true is set, store them on the ssoProvider row without origin validation, and fetch them during OIDC callback, allowing non-blind server-side request forgery and possible account linking when trustEmailVerified: true is configured. This issue is fixed in version 1.6.11.
- Record
CVE-2026-53513- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-20, CWE-345, CWE-441, CWE-918
- Updated
- 2026-11-02
OSVGHSA-5rr4-8452-hf4v
9.6
@better-auth/sso provider registration has server-side request forgery via unvalidated OIDC endpoints
Am I affected?
Users are affected if all of the following are true:
- Their application uses
@better-auth/ssoat a version>= 0.1.0, < 1.6.11on the stable line, or any1.7.0-beta.xon the pre-release line. - The
sso()plugin is added to their application'sbetterAuth({ plugins: [...] })array. - Any user with a valid Better Auth session can reach
POST /sso/register(the plugin's default gate accepts any session).
For the non-blind SSRF impact (full IAM credential or internal HTTP body exfiltration), no further configuration is required.
For the account takeover escalation, additionally:
- Developers set
sso({ trustEmailVerified: true, ... }). - The developer's application deployment has accounts whose
emailoverlaps with attacker-chosen domains.
If developers do not enable the SSO plugin, their application is not affected.
Fix:
- Upgrade to
@better-auth/[email protected]or later. - If developers cannot upgrade, see workarounds below.
Summary
The @better-auth/sso plugin's POST /sso/register endpoint accepts attacker-controlled oidcConfig.userInfoEndpoint, tokenEndpoint, and jwksEndpoint URLs when skipDiscovery: true is set, persists them on the ssoProvider row without origin validation, then issues server-side fetches to those URLs during the OIDC callback. The fetched response body is reflected through the user profile, producing a non-blind SSRF reachable by any authenticated session. The same primitive exists on POST /sso/update-provider.
Details
The schema field types accept bare strings: no .url() validator, no origin gate. The discovery branch (skipDiscovery: false) routes URLs through validateDiscoveryUrl; the skip-discovery branch persists them as-is. At callback time three fetch sites read the stored URLs: validateAuthorizationCode for the token endpoint, betterFetch for the userInfo endpoint, and validateToken for the JWKS endpoint.
When trustEmailVerified: true is configured, the attacker can escalate to account linking. A malicious userInfo response with emailVerified: true and a chosen email triggers OAuth auto-link against any pre-existing user row with that email, compounding the SSRF into account takeover.
Patches
Fixed in @better-auth/[email protected]. Provider registration (POST /sso/register with skipDiscovery: true) and every POST /sso/update-provider request now validate each supplied OIDC endpoint URL (authorizationEndpoint, tokenEndpoint, userInfoEndpoint, jwksEndpoint, discoveryEndpoint) at registration time. A URL is rejected unless it satisfies one of two conditions:
- Its host is publicly routable on the internet, evaluated through the
@better-auth/core/utils/host.isPublicRoutableHostgate. RFC 1918 private ranges, RFC 4193 unique-local addresses, link-local addresses (including the cloud-metadata IP169.254.169.254), loopback, multicast, broadcast, and reserved ranges are rejected, along with cloud-metadata FQDNs. - Its origin is already listed in the application's
trustedOriginsconfiguration. This preserves the documented escape hatch for customers running internal IdPs intentionally on private networks.
The schema also tightens from z.string() to z.url() on those fields, so malformed URLs fail at parse time rather than at fetch time. Deployments running internal IdPs that previously worked must add the IdP's origin to trustedOrigins to keep working after upgrade.
Workarounds
If developers cannot upgrade immediately:
- Disable provider self-registration: set
sso({ providersLimit: 0 }). The limit is enforced before the schema branch, blocking every/sso/registerregardless ofskipDiscovery. - Reverse-proxy gate: block
POST /sso/registerandPOST /sso/update-providerat the edge, or restrict to a denylist of source IPs and a small admin user list. - Network-level egress controls: block egress from the auth server to RFC 1918, RFC 4193, link-local ranges…
- Record
GHSA-5rr4-8452-hf4v- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-20, CWE-345, CWE-441, CWE-918
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@better-auth/ssonpm |
0.1.0 up to 1.6.11 | 1.6.11 |
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-53513 is a critical vulnerability (CVSS 9.6) in @better-auth Sso, published July 7, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.25%, the 16th percentile. Fixed in @better-auth/sso 1.6.11.
References
github.com/better-auth/better-auth/security/advisories/GHSA-5rr4-8452-hf4v
github.com/better-auth/better-auth/pull/9574
github.com/better-auth/better-auth/commit/37f60cb176cb53147da7dfd5ec15afa5b486e81e
github.com/better-auth/better-auth/releases/tag/v1.6.11
nvd.nist.gov/vuln/detail/CVE-2026-53513
github.com/advisories/GHSA-5rr4-8452-hf4v
github.com/CVEProject/cvelistV5/tree/main/cves/2026/53xxx/CVE-2026-53513.json
github.com/better-auth/better-auth
Left out here: the rest of 2 source descriptions. The JSON record has them.