CWE-41
AllowedImproper Resolution of Path Equivalence
Abstraction: Base · Status: Incomplete
The product is vulnerable to file system contents disclosure through path equivalence. Path equivalence involves the use of special characters in file and directory names. The associated manipulations are intended to generate multiple names for the same object.
66 vulnerabilities reference this CWE, most recent first.
GHSA-QCXP-GM7M-4J5V
Vulnerability from github – Published: 2026-07-29 15:40 – Updated: 2026-07-30 12:32Quarkus HTTP path-based authorization policies can be bypassed using encoded semicolons (%3B) to smuggle matrix parameters past the security layer, and using encoded slashes (%2F) or backslashes (%5C) to access protected static resources. This is a distinct issue from CVE-2026-39852, which addressed only literal semicolon stripping.
### Technical Details
The security layer (AbstractPathMatchingHttpSecurityPolicy) normalizes request paths using Vert.x's normalizedPath(), which only decodes unreserved RFC 3986 characters (letters, digits, -, ., _, ~). It then strips matrix parameters by looking for literal ; characters. This creates two mismatches:
- Encoded semicolons (
%3B): Since%3Bis not decoded by normalizedPath(), the matrix parameter stripping in pathWithoutMatrixParams() never sees it. The encoded semicolon and everything after it become part of the path segment, causing policy matching to fail. This affects all path-policy-protected endpoints. - Static resource path mismatch: Static resource handlers (StaticHandlerImpl, FileSystemStaticHandler) perform full
percent-decoding via URIDecoder.decodeURIComponent() and backslash-to-slash conversion before filesystem resolution.
Reserved characters like
%2F(slash) and%5C(backslash) that survive the security layer's partial decoding are fully decoded before file serving.
REST endpoints using Quarkus REST (RESTEasy Reactive) are not affected by the %2F/%5C vectors because the routing layer also uses normalizedPath() — both security and routing agree on the path, so no mismatch exists.
Attack Vectors
Encoded semicolon (matrix parameter smuggling), affects all path-policy-protected endpoints:
/api/admin%3Bbypass=true/data: security sees this as a single segmentadmin%3Bbypass=true, which does not match the/api/admin/* policy. The request passes through unauthenticated./api/secret%3b/data: same mechanism with lowercase hex digit.
Encoded slash/backslash on static resources, affects static files behind path policies:
- /static-secret%2Fhtml, security does not match /static-secret.html policy; static handler decodes %2F to / and may
resolve the file.
- /static-secret%5Chtml. static handler decodes %5C to \, then converts to /.
Double encoding, affects static resources:
- /secret%252Fconfidential.html, first decode by normalizedPath() turns %25 into %, producing %2F. Static handler's
second decode turns %2F into /.
The following vectors were investigated and confirmed not exploitable:
- Unreserved character encoding (
/api/adm%69n/data):normalizedPath()decodes these. Both security and routing see/api/admin/data. - Null byte injection (
/api/admin%00/data):%00is not decoded bynormalizedPath(). - Encoded dot segments (
/api/%2e%2e/secret/data): Period is unreserved, so%2eis decoded to.bynormalizedPath(), thenremoveDots()normalizes..segments. - REST endpoint bypass via
%2F/%5C: Routing uses the samenormalizedPath()as security. The encoded slash/backslash doesn't match any route.
Root Cause
pathWithoutMatrixParams() operates on the partially-decoded output of normalizedPath(), where reserved characters
remain encoded. It searches for literal ; but never sees %3B. The fix (normalizePath()) performs full percent-decoding
in a loop before stripping matrix parameters, removing null bytes, normalizing backslashes, and resolving dot
segments, aligning the security layer's view of the path with what downstream handlers resolve.
Impact
- Unauthenticated access to endpoints protected by
quarkus.http.auth.permissionpath-based policies via%3Bsmuggling - Static resource exposure by bypassing path policies on protected files via
%2F/%5C - Applications using annotation-based security (
@RolesAllowed,@Authenticated) on JAX-RS resources without path-based policies are not affected by the%2F/%5Cvectors, but may still be affected by%3Bif path policies coexist
Proof of Concept
# Encoded semicolon bypass — works on any path-policy-protected endpoint
# Security sees "/api/admin%3Bbypass=true/data", doesn't match /api/admin/* policy
curl -v http://target/api/admin%3Bbypass=true/data
# Encoded semicolon on authenticated endpoint
curl -v http://target/api/secret%3b/data
# Static resource bypass via encoded slash (if static file behind path policy)
curl -v http://target/static-secret%2Fhtml
# Static resource bypass via encoded backslash
curl -v http://target/static-secret%5Chtml
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "io.quarkus:quarkus-vertx-http"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.20.6.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "io.quarkus:quarkus-vertx-http"
},
"ranges": [
{
"events": [
{
"introduced": "3.21.0.CR1"
},
{
"fixed": "3.27.4.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "io.quarkus:quarkus-vertx-http"
},
"ranges": [
{
"events": [
{
"introduced": "3.28.0.CR1"
},
{
"fixed": "3.33.2.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "io.quarkus:quarkus-vertx-http"
},
"ranges": [
{
"events": [
{
"introduced": "3.34.0.CR1"
},
{
"fixed": "3.36.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "io.quarkus:quarkus-vertx-http"
},
"ranges": [
{
"events": [
{
"introduced": "3.37.0.CR1"
},
{
"fixed": "3.37.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-50559"
],
"database_specific": {
"cwe_ids": [
"CWE-178",
"CWE-287",
"CWE-41",
"CWE-551",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-29T15:40:05Z",
"nvd_published_at": "2026-06-19T21:17:02Z",
"severity": "HIGH"
},
"details": "Quarkus HTTP path-based authorization policies can be bypassed using encoded semicolons (%3B) to smuggle matrix\n parameters past the security layer, and using encoded slashes (%2F) or backslashes (%5C) to access protected static\n resources. This is a distinct issue from CVE-2026-39852, which addressed only literal semicolon stripping.\n\n ### Technical Details\n\n The security layer (AbstractPathMatchingHttpSecurityPolicy) normalizes request paths using Vert.x\u0027s normalizedPath(),\n which only decodes unreserved RFC 3986 characters (letters, digits, -, ., _, ~). It then strips matrix parameters by\n looking for literal ; characters. This creates two mismatches:\n\n 1. Encoded semicolons (`%3B`): Since `%3B` is not decoded by normalizedPath(), the matrix parameter stripping in\n pathWithoutMatrixParams() never sees it. The encoded semicolon and everything after it become part of the path\n segment, causing policy matching to fail. This affects all path-policy-protected endpoints.\n 2. Static resource path mismatch: Static resource handlers (StaticHandlerImpl, FileSystemStaticHandler) perform full\n percent-decoding via URIDecoder.decodeURIComponent() and backslash-to-slash conversion before filesystem resolution.\n Reserved characters like `%2F` (slash) and `%5C` (backslash) that survive the security layer\u0027s partial decoding are fully\n decoded before file serving.\n\n REST endpoints using Quarkus REST (RESTEasy Reactive) are not affected by the `%2F/%5C` vectors because the routing layer also uses `normalizedPath()` \u2014 both security and routing agree on the path, so no mismatch exists.\n\n### Attack Vectors\n\n Encoded semicolon (matrix parameter smuggling), affects all path-policy-protected endpoints:\n \n - `/api/admin%3Bbypass=true/data`: security sees this as a single segment `admin%3Bbypass=true`, which does not match the\n `/api/admin/* policy`. The request passes through unauthenticated.\n - `/api/secret%3b/data`: same mechanism with lowercase hex digit.\n\n Encoded slash/backslash on static resources, affects static files behind path policies:\n - `/static-secret%2Fhtml`, security does not match /static-secret.html policy; static handler decodes `%2F` to `/` and may\n resolve the file.\n - `/static-secret%5Chtml `. static handler decodes `%5C` to `\\`, then converts to `/`.\n\n Double encoding, affects static resources:\n - `/secret%252Fconfidential.html`, first decode by normalizedPath() turns `%25` into `%`, producing `%2F`. Static handler\u0027s\n second decode turns `%2F` into `/`.\n\n The following vectors were investigated and confirmed not exploitable:\n\n - Unreserved character encoding (`/api/adm%69n/data`): `normalizedPath()` decodes these. Both security and routing see\n `/api/admin/data`. \n - Null byte injection (`/api/admin%00/data`): `%00` is not decoded by `normalizedPath()`. \n - Encoded dot segments (`/api/%2e%2e/secret/data`): Period is unreserved, so `%2e` is decoded to `.` by `normalizedPath()`,\n then `removeDots()` normalizes `..` segments. \n - REST endpoint bypass via `%2F/%5C`: Routing uses the same `normalizedPath()` as security. The encoded slash/backslash\n doesn\u0027t match any route. \n\n### Root Cause\n\n `pathWithoutMatrixParams()` operates on the partially-decoded output of `normalizedPath()`, where reserved characters\n remain encoded. It searches for literal ; but never sees `%3B.` The fix (`normalizePath()`) performs full percent-decoding\n in a loop before stripping matrix parameters, removing null bytes, normalizing backslashes, and resolving dot\n segments, aligning the security layer\u0027s view of the path with what downstream handlers resolve.\n\n### Impact\n\n - Unauthenticated access to endpoints protected by `quarkus.http.auth.permission` path-based policies via `%3B` smuggling\n - Static resource exposure by bypassing path policies on protected files via `%2F/%5C`\n - Applications using annotation-based security (`@RolesAllowed`, `@Authenticated`) on JAX-RS resources without path-based\n policies are not affected by the `%2F/%5C` vectors, but may still be affected by `%3B` if path policies coexist\n\n### Proof of Concept\n\n```\n # Encoded semicolon bypass \u2014 works on any path-policy-protected endpoint\n # Security sees \"/api/admin%3Bbypass=true/data\", doesn\u0027t match /api/admin/* policy\n curl -v http://target/api/admin%3Bbypass=true/data\n\n # Encoded semicolon on authenticated endpoint\n curl -v http://target/api/secret%3b/data\n\n # Static resource bypass via encoded slash (if static file behind path policy)\n curl -v http://target/static-secret%2Fhtml\n\n # Static resource bypass via encoded backslash\n curl -v http://target/static-secret%5Chtml\n```",
"id": "GHSA-qcxp-gm7m-4j5v",
"modified": "2026-07-30T12:32:16Z",
"published": "2026-07-29T15:40:05Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/quarkusio/quarkus/security/advisories/GHSA-qcxp-gm7m-4j5v"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-50559"
},
{
"type": "WEB",
"url": "https://github.com/quarkusio/quarkus/commit/919b80017d85564143a845b38e9cca54aff5b3cc"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:26017"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:26018"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:26194"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:26586"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:34608"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:36820"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:48151"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2026-50559"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2486959"
},
{
"type": "PACKAGE",
"url": "https://github.com/quarkusio/quarkus"
},
{
"type": "WEB",
"url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-50559.json"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Quarkus: Authentication/Authorization Bypass via Advanced Path Normalization Vulnerabilities"
}
GHSA-R5JH-Q2MW-GCX4
Vulnerability from github – Published: 2026-07-28 20:18 – Updated: 2026-07-28 20:18SanitizeFilePath in pkg/utils/utils.go validated that a path stayed under a safe directory by calling strings.HasPrefix(path, safedir). This is a lexical check, not a directory boundary check: /packages-extra/evil starts with
/packages, so it passed. The function did not enforce a path-separator boundary, so any sibling directory whose name began with the safe-directory string was accepted.
Callers included the builder's Clean handler (pkg/builder/builder.go:208) and the fetcher's Fetch / Upload handlers (pkg/fetcher/fetcher.go). A tenant who could pre-create or control a sibling directory under the fetcher /
builder's shared volume could induce a write or read outside the intended safe directory.
Affected
- Project:
github.com/fission/fission - Versions: all versions through v1.24.0 with
SanitizeFilePathin the tree - Audited commit:
647c141 - Component:
pkg/utils/utils.go:SanitizeFilePath - Callers:
pkg/builder/builder.go:157,164,208,pkg/fetcher/fetcher.go:296,311,450,496,565,571 - Configuration: default; requires a sibling directory to the safe dir to exist on the filesystem
Fix section (paste into the Fix / Patches field)
Fixed in v1.25.0 by:
- PR #3445 (commit
8298e33e) — migrate everySanitizeFilePathcall site (fetcher:storePath/tmpPath/secretDir/configDir/ rename +writeSecretOrConfigMap; builder:srcPkg/deployPkgpath validation andsrcPkgstat) to newpkg/utils/root.gohelpers (RootJoin,RootStat,RootWriteFile,RootMkdirAll,RootRename) that operate throughos.Root.os.Rootenforces directory confinement in the kernel and is recognized by CodeQLgo/path-injectionas a traversal barrier. - PR #3446 (commit
5aac6f0b) — delete the deprecatedSanitizeFilePathitself once no callers remained. The vulnerable function no longer exists in the tree.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.24.0"
},
"package": {
"ecosystem": "Go",
"name": "github.com/fission/fission"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.25.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-50568"
],
"database_specific": {
"cwe_ids": [
"CWE-41"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-28T20:18:30Z",
"nvd_published_at": "2026-06-10T18:17:13Z",
"severity": "LOW"
},
"details": "`SanitizeFilePath` in `pkg/utils/utils.go` validated that a path stayed under a safe directory by calling `strings.HasPrefix(path, safedir)`. This is a lexical check, not a directory boundary check: `/packages-extra/evil` starts with\n`/packages`, so it passed. The function did not enforce a path-separator boundary, so any sibling directory whose name began with the safe-directory string was accepted.\n\nCallers included the builder\u0027s `Clean` handler (`pkg/builder/builder.go:208`) and the fetcher\u0027s `Fetch` / `Upload` handlers (`pkg/fetcher/fetcher.go`). A tenant who could pre-create or control a sibling directory under the fetcher /\nbuilder\u0027s shared volume could induce a write or read outside the intended safe directory.\n\n### Affected\n\n- Project: `github.com/fission/fission`\n- Versions: all versions through v1.24.0 with `SanitizeFilePath` in the tree\n- Audited commit: `647c141`\n- Component: `pkg/utils/utils.go:SanitizeFilePath`\n- Callers: `pkg/builder/builder.go:157,164,208`, `pkg/fetcher/fetcher.go:296,311,450,496,565,571`\n- Configuration: default; requires a sibling directory to the safe dir to exist on the filesystem\n\n\nFix section (paste into the Fix / Patches field)\n\nFixed in [v1.25.0](https://github.com/fission/fission/releases/tag/v1.25.0) by:\n\n- [PR #3445](https://github.com/fission/fission/pull/3445) (commit [`8298e33e`](https://github.com/fission/fission/commit/8298e33ea7457702f893eae11077987cf905edb4)) \u2014 migrate every `SanitizeFilePath` call site (fetcher: `storePath` /\n`tmpPath` / `secretDir` / `configDir` / rename + `writeSecretOrConfigMap`; builder: `srcPkg` / `deployPkg` path validation and `srcPkg` stat) to new `pkg/utils/root.go` helpers (`RootJoin`, `RootStat`, `RootWriteFile`, `RootMkdirAll`,\n`RootRename`) that operate through `os.Root`. `os.Root` enforces directory confinement in the kernel and is recognized by CodeQL `go/path-injection` as a traversal barrier.\n- [PR #3446](https://github.com/fission/fission/pull/3446) (commit [`5aac6f0b`](https://github.com/fission/fission/commit/5aac6f0bcdf840e28f3f06c846ca7ae1866b3957)) \u2014 delete the deprecated `SanitizeFilePath` itself once no callers\nremained. The vulnerable function no longer exists in the tree.",
"id": "GHSA-r5jh-q2mw-gcx4",
"modified": "2026-07-28T20:18:30Z",
"published": "2026-07-28T20:18:30Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/fission/fission/security/advisories/GHSA-r5jh-q2mw-gcx4"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-50568"
},
{
"type": "WEB",
"url": "https://github.com/fission/fission/pull/3445"
},
{
"type": "WEB",
"url": "https://github.com/fission/fission/pull/3446"
},
{
"type": "WEB",
"url": "https://github.com/fission/fission/commit/5aac6f0bcdf840e28f3f06c846ca7ae1866b3957"
},
{
"type": "WEB",
"url": "https://github.com/fission/fission/commit/8298e33ea7457702f893eae11077987cf905edb4"
},
{
"type": "PACKAGE",
"url": "https://github.com/fission/fission"
},
{
"type": "WEB",
"url": "https://github.com/fission/fission/releases/tag/v1.25.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Fission: SanitizeFilePath lexical HasPrefix bypass permits sibling-directory escape"
}
GHSA-VP5Q-499V-968R
Vulnerability from github – Published: 2025-01-14 18:32 – Updated: 2025-01-14 18:32MapUrlToZone Security Feature Bypass Vulnerability
{
"affected": [],
"aliases": [
"CVE-2025-21268"
],
"database_specific": {
"cwe_ids": [
"CWE-41"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-01-14T18:15:46Z",
"severity": "MODERATE"
},
"details": "MapUrlToZone Security Feature Bypass Vulnerability",
"id": "GHSA-vp5q-499v-968r",
"modified": "2025-01-14T18:32:03Z",
"published": "2025-01-14T18:32:03Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-21268"
},
{
"type": "WEB",
"url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-21268"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-W4H3-GPV2-82QC
Vulnerability from github – Published: 2026-04-01 18:36 – Updated: 2026-04-01 18:36OpenClaw before 2026.3.22 contains a path traversal vulnerability in Windows media loaders that accepts remote-host file URLs and UNC-style paths before local-path validation. Attackers can exploit this by providing network-hosted file targets that are treated as local content, bypassing intended access restrictions.
{
"affected": [],
"aliases": [
"CVE-2026-34510"
],
"database_specific": {
"cwe_ids": [
"CWE-41"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-01T16:23:50Z",
"severity": "MODERATE"
},
"details": "OpenClaw before 2026.3.22 contains a path traversal vulnerability in Windows media loaders that accepts remote-host file URLs and UNC-style paths before local-path validation. Attackers can exploit this by providing network-hosted file targets that are treated as local content, bypassing intended access restrictions.",
"id": "GHSA-w4h3-gpv2-82qc",
"modified": "2026-04-01T18:36:36Z",
"published": "2026-04-01T18:36:36Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-h3x4-hc5v-v2gm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34510"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/4fd7feb0fd4ec16c48ed983980dba79a09b3aaf5"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/630f1479c44f78484dfa21bb407cbe6f171dac87"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/93880717f1cd34feaa45e74e939b7a5256288901"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/openclaw-remote-file-url-acceptance-in-windows-media-loaders"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/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",
"type": "CVSS_V4"
}
]
}
GHSA-X732-6J76-QMHM
Vulnerability from github – Published: 2025-12-16 21:22 – Updated: 2025-12-16 21:22Summary
An 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.
Details
Better Auth uses better-call, which internally relies on rou3 for routing. Affected versions of rou3 normalize paths by removing empty segments. As a result:
/sign-in/email//sign-in/email///sign-in/email
…all resolve to the same route.
Some production setups automatically collapse multiple slashes. This includes:
- Vercel with Nextjs (default)
- Cloudflare - when normalize to urls origin is enabled (https://developers.cloudflare.com/rules/normalization/settings/#normalize-urls-to-origin)
In these environments and other configurations where //path reach Better Auth as /path, the issue does not apply.
Fix
Updating rou3 to the latest version resolves the issue:
- better-call previously depended on
"rou3": "^0.5.1" - The fix was introduced after that version (commit: https://github.com/h3js/rou3/commit/f60b43fa648399534507c9ac7db36d705b8874c3)
Better Auth recommends:
- Upgrading to Better Auth v1.4.5 or later, which includes the updated rou3.
- Ensuring the proxy normalizes URLs.
- If project maintainers cannot upgrade yet, they can protect their app by normalizing url before it reaches better-auth handler. See example below:
const req = new Request(...) // this would be the actual request object
const url = new URL(req.url);
const normalizedPath = url.pathname.replace(/\/+/g, "/");
if (url.pathname !== normalizedPath) {
url.pathname = normalizedPath;
// Update the raw request pathname
Object.defineProperty(req, "url", {
value: url.toString(),
writable: true,
configurable: true,
});
}
Impact
- Bypass
disabledPaths - Bypass path-based rate limits
The impact of bypassing disabled paths could vary based on a project's configuration.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "better-auth"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.4.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-400",
"CWE-41"
],
"github_reviewed": true,
"github_reviewed_at": "2025-12-16T21:22:45Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"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\u2026all 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\u0027s configuration.",
"id": "GHSA-x732-6j76-qmhm",
"modified": "2025-12-16T21:22:45Z",
"published": "2025-12-16T21:22:45Z",
"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"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H",
"type": "CVSS_V3"
}
],
"summary": "Better Auth\u0027s rou3 Dependency has Double-Slash Path Normalization which can Bypass disabledPaths Config and Rate Limits"
}
GHSA-XGHP-74WC-WJG3
Vulnerability from github – Published: 2024-09-10 18:30 – Updated: 2024-09-10 18:30Windows Security Zone Mapping Security Feature Bypass Vulnerability
{
"affected": [],
"aliases": [
"CVE-2024-30073"
],
"database_specific": {
"cwe_ids": [
"CWE-41"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-09-10T17:15:16Z",
"severity": "HIGH"
},
"details": "Windows Security Zone Mapping Security Feature Bypass Vulnerability",
"id": "GHSA-xghp-74wc-wjg3",
"modified": "2024-09-10T18:30:44Z",
"published": "2024-09-10T18:30:44Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-30073"
},
{
"type": "WEB",
"url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-30073"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
Mitigation MIT-5
Strategy: Input Validation
- Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does.
- When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
- Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
Mitigation MIT-30
Strategy: Output Encoding
Use and specify an output encoding that can be handled by the downstream component that is reading the output. Common encodings include ISO-8859-1, UTF-7, and UTF-8. When an encoding is not specified, a downstream component may choose a different encoding, either by assuming a default encoding or automatically inferring which encoding is being used, which can be erroneous. When the encodings are inconsistent, the downstream component might treat some character or byte sequences as special, even if they are not special in the original encoding. Attackers might then be able to exploit this discrepancy and conduct injection attacks; they even might be able to bypass protection mechanisms that assume the original encoding is also being used by the downstream component.
Mitigation MIT-20
Strategy: Input Validation
Inputs should be decoded and canonicalized to the application's current internal representation before being validated (CWE-180). Make sure that the application does not decode the same input twice (CWE-174). Such errors could be used to bypass allowlist validation schemes by introducing dangerous inputs after they have been checked.
CAPEC-3: Using Leading 'Ghost' Character Sequences to Bypass Input Filters
Some APIs will strip certain leading characters from a string of parameters. An adversary can intentionally introduce leading "ghost" characters (extra characters that don't affect the validity of the request at the API layer) that enable the input to pass the filters and therefore process the adversary's input. This occurs when the targeted API will accept input data in several syntactic forms and interpret it in the equivalent semantic way, while the filter does not take into account the full spectrum of the syntactic forms acceptable to the targeted API.