Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
📦
📦 npm
Not in CISA KEV
HIGH severity

GHSA-p6v2-xcpg-h6xw

HIGHFix: better-auth/better-auth#7470

GHSA-p6v2-xcpg-h6xw is a high-severity (CVSS 7.3) vulnerability in better-auth. O3 Security confirms whether GHSA-p6v2-xcpg-h6xw is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.

Better Auth: Rate limiter keys IPv6 addresses individually and is bypassable via prefix rotation

Also known asCVE-2026-45364
Published
May 15, 2026
Updated
Jun 9, 2026
Affected
2 pkgs
Patched
2 / 2
Exploits
None indexed
Exploitation data as of Jun 9, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

2 pkgs affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, a proxy for how much of the ecosystem is exposed.

better-authnpm
6.5Mdownloads / week

Description

Am I affected?

Users are affected if all of the following are true:

  • Their app uses better-auth at a version < 1.4.17, or at a v1.5 prerelease tagged <= 1.5.0-beta.8.
  • The apps authentication endpoints serve clients reachable over IPv6. Most managed hosts including Cloudflare, Vercel, Fly.io, AWS Application Load Balancer, and Google Cloud Load Balancing advertise IPv6 by default.
  • The app's rate-limit configuration is enabled (the production default) and relies on the leftmost x-forwarded-for value (the stock setup) or any other configured IP-bearing header.

If users are on 1.4.16 specifically, the normalizeIP helper exists in your version but the IPv6 prefix length defaults to /128. Stock config still permits prefix rotation because no prefix mask is applied. Either upgrade to 1.4.17 or set advanced.ipAddress.ipv6Subnet: 64 in the config.

If applications do not use the rate limiter, or if the deployment serves only IPv4 clients, the prefix-rotation vector does not apply. The representation-aliasing vector still applies to IPv6 addresses delivered over IPv4 transport in some edge cases (an upstream proxy carrying an IPv4-mapped IPv6 source), but it is rare in practice.

Fix:

  1. Upgrade to [email protected] or later. The current stable line 1.6.x and the pre-release line 1.7.0-beta both carry the fix.
  2. If applications cannot upgrade, see workarounds below.

Summary

Better Auth's HTTP rate limiter keyed each request by the exact textual IP address it received in x-forwarded-for (or the configured IP-bearing header). IPv6 clients controlling a typical /64 allocation could rotate through 2^64 distinct source addresses without exhausting the per-address counter, defeating rate limiting on /sign-in/email, /sign-up/email, /forget-password, and every other path the limiter protects. The same bug allowed a single client to vary the textual encoding of one IPv6 address (uppercase, compression, IPv4-mapped, hex-encoded IPv4-in-IPv6) and produce multiple distinct keys.

Details

The pre-fix getIp function returned the leftmost x-forwarded-for value verbatim after a single validity check, and onRequestRateLimit constructed the rate-limit key by string concatenation of that value with the request path. Two facts of IPv6 made the key space larger than the population of clients:

  • ISPs and cloud providers assign prefixes, not addresses. RFC 6177 recommends /56 for residential users; cloud providers commonly assign /29 to /48. An attacker controlling a single /64 therefore controls 2^64 source addresses without doing anything unusual.
  • IPv6 has multiple textual representations for the same address. RFC 5952 specifies a canonical form, but RFC 4291 §2.2 permits the older mixed forms, and ::ffff:0:0/96 IPv4-mapped addresses can be written as either dotted-decimal or hex-encoded.

The fix in [email protected] introduces normalizeIP and applies it to every getIp result. Normalization expands compressed IPv6 forms, lowercases hex digits, collapses IPv4-mapped IPv6 to plain IPv4, and applies a default /64 prefix mask. The rate-limit key construction now uses an explicit | separator to prevent key-construction collisions across address-and-path joins.

The /64 default matches the smallest commonly-allocated IPv6 unit, so a single client cannot use prefix rotation to defeat rate limiting on stock config. Operators who serve clients on coarser allocations (/56 for residential ISPs, larger for cloud) can configure advanced.ipAddress.ipv6Subnet accordingly.

Patches

Fixed in [email protected] on the v1.4.x maintenance line and in [email protected] on the v1.5.x line. PR #7470 introduced the normalization primitive (packages/core/src/utils/ip.ts) and applied it to getIp and the rate-limit key. PR #7509 changed the IPv6 prefix-length default from /128 to /64 so that stock config closes the prefix-rotation vector without requiring users to opt in.

After the patch, the rate limiter treats all IPv6 addresses within a /64 allocation as a single client, all textual encodings of one IPv6 address as the same address, and all IPv4-mapped IPv6 addresses as their underlying IPv4 form.

Workarounds

If users cannot upgrade past 1.4.17:

  • On >= 1.4.16: set advanced.ipAddress.ipv6Subnet: 64 in the auth configuration. The normalizeIP helper is present at 1.4.16; only the default is wrong. This restores the post-1.4.17 behavior on stock config.
  • On < 1.4.16: shift the bypass mitigation upstream. Set the IPv6 prefix length on the app's CDN, WAF, or load balancer rate-limit policy to /64 (or coarser per RFC 6177 if the app serves residential traffic). Cloudflare, Vercel Firewall, AWS WAF, and Google Cloud Armor all support per-prefix rate limiting.
  • As a partial mitigation on any version: tighten the customRules window for sign-in, sign-up, and password-reset endpoints. This narrows the abuse window but does not close it.

Impact

The bypass enables unbounded authentication attempts from a single IPv6-capable client. Direct consequences:

  • Credential-stuffing and brute-force on /sign-in/email are no longer rate-limited per client.
  • Account enumeration via response-shape differences becomes faster.
  • Password-reset and email-verification email fan-out can be amplified.

The bypass does not directly compromise any account. Successful exploitation still requires the attacker to guess a credential the password store accepts. The rating reflects the loss of one defense-in-depth layer rather than a direct compromise.

Credit

Reported by @nexryai on GitHub.

Resources

Affected Packages

2 total 2 fixed
EcosystemPackageVulnerable rangeFix
📦npmbetter-authall versions1.4.17
📦npmbetter-auth1.5.0-beta.1&&< 1.5.0-beta.91.5.0-beta.9

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for better-auth. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update better-auth to 1.4.17 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-p6v2-xcpg-h6xw is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-p6v2-xcpg-h6xw is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-p6v2-xcpg-h6xw. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

### Am I affected? Users are affected if all of the following are true: - Their app uses `better-auth` at a version `< 1.4.17`, or at a v1.5 prerelease tagged `<= 1.5.0-beta.8`. - The apps authentication endpoints serve clients reachable over IPv6. Most managed hosts including Cloudflare, Vercel, Fly.io, AWS Application Load Balancer, and Google Cloud Load Balancing advertise IPv6 by default. - The app's rate-limit configuration is enabled (the production default) and relies on the leftmost `x-forwarded-for` value (the stock setup) or any other configured IP-bearing header. If users are on
O3 Security · Impact-Aware SCA

Is GHSA-p6v2-xcpg-h6xw in your dependencies?

O3 detects GHSA-p6v2-xcpg-h6xw across npm dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.

GHSA-p6v2-xcpg-h6xw: better-auth (High 7.3) | O3 Security