{"id":"GHSA-x732-6j76-qmhm","summary":"Better Auth's rou3 Dependency has Double-Slash Path Normalization which can Bypass disabledPaths Config and Rate Limits","details":"## Summary\n\nAn issue in the underlying router library **rou3** can cause `/path` and `//path` to be treated as identical routes. If your environment does **not** normalize incoming URLs (e.g., by collapsing multiple slashes), this can allow bypasses of `disabledPaths` and path-based rate limits.\n\n## Details\n\nBetter Auth uses **better-call**, which internally relies on **rou3** for routing. Affected versions of rou3 normalize paths by removing empty segments. As a result:\n\n* `/sign-in/email`\n* `//sign-in/email`\n* `///sign-in/email`\n\n…all resolve to the same route.\n\nSome production setups *automatically* collapse multiple slashes. This includes:\n\n* Vercel with Nextjs (default)\n* Cloudflare - when normalize to urls origin is enabled (https://developers.cloudflare.com/rules/normalization/settings/#normalize-urls-to-origin)\n\nIn these environments and other configurations where `//path` reach Better Auth as `/path`, the issue does not apply.\n\n## Fix\n\nUpdating rou3 to the latest version resolves the issue:\n\n* better-call previously depended on `\"rou3\": \"^0.5.1\"`\n* The fix was introduced after that version\n  (commit: [https://github.com/h3js/rou3/commit/f60b43fa648399534507c9ac7db36d705b8874c3](https://github.com/h3js/rou3/commit/f60b43fa648399534507c9ac7db36d705b8874c3))\n\nBetter Auth recommends:\n\n1. **Upgrading to Better Auth v1.4.5 or later**, which includes the updated rou3.\n2. Ensuring the proxy normalizes URLs.\n3. If project maintainers cannot upgrade yet, they can protect their app by normalizing url before it reaches better-auth handler. See example below:\n```ts\nconst req = new Request(...) // this would be the actual request object\nconst url = new URL(req.url);\nconst normalizedPath = url.pathname.replace(/\\/+/g, \"/\");\n\nif (url.pathname !== normalizedPath) {\n  url.pathname = normalizedPath;\n  // Update the raw request pathname\n  Object.defineProperty(req, \"url\", {\n    value: url.toString(),\n    writable: true,\n    configurable: true,\n  });\n}\n```\n\n## Impact\n\n* Bypass `disabledPaths`\n* Bypass path-based rate limits\n\nThe impact of bypassing disabled paths could vary based on a project's configuration.","aliases":["CVE-2025-71399"],"modified":"2026-08-03T03:41:44.584235266Z","published":"2025-12-16T21:22:45Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2025-12-16T21:22:45Z","nvd_published_at":null,"cwe_ids":["CWE-400","CWE-41"],"severity":"HIGH"},"references":[{"type":"WEB","url":"https://github.com/better-auth/better-auth/security/advisories/GHSA-x732-6j76-qmhm"},{"type":"PACKAGE","url":"https://github.com/better-auth/better-auth"}],"affected":[{"package":{"name":"better-auth","ecosystem":"npm","purl":"pkg:npm/better-auth"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.4.5"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/12/GHSA-x732-6j76-qmhm/GHSA-x732-6j76-qmhm.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H"}]}