GHSA-cxjq-mrr5-89rv Traefik: Authentication Bypass via Path Traversal in ReplacePathRegex Middleware
SummaryThere is a critical authentication-bypass vulnerability in Traefik's `ReplacePathRegex` middleware. When it is configured with a regular expression that captures user-controlled path segments without a mandatory separator (for example `regex: "^/api(.*)"`, `replacement: "/$1"`), a crafted request can produce an un-normalized replacement path such as `/../admin`, which Traefik forwarded to the backend without validation. A backend that normalizes the path may resolve it to a protected route, letting an unauthenticated attacker reach resources located behind authentication middleware. This is the same class of issue that was fixed for `StripPrefix` in CVE-2026-48020; that post-replacement normalization check had not been applied to `ReplacePathRegex`. The fix rejects any request whose replaced path does not match its normalized form.Patcheshttps://github.com/traefik/traefik/releases/tag/v2.11.52https://github.com/traefik/traefik/releases/tag/v3.6.23https://github.com/traefik/traefik/releases/tag/v3.7.7For more informationIf you have any questions or comments about this advisory, please [open an issue](https://github.com/traefik/traefik/issues).SummaryA path traversal vulnerability in the ReplacePathRegex middleware allows an unauthenticated remote attacker to bypass authentication middleware and access protected routes by sending a single crafted HTTP request. The vulnerability exists because ReplacePathRegex does not perform post-replacement path normalization validation - the same check added to StripPrefix in the fix for CVE-2026-48020 was not applied to ReplacePathRegex.DetailsWhen ReplacePathRegex is configured with a regex that captures user-controlled path segments without a mandatory path separator (e.g., `regex: "^/api(.*)"`, `replacement: "/$1"`), an attacker can inject implicit traversal sequences into the capture group.**Root cause:** `pkg/middlewares/replacepathregex/replace_path_regex.go`, function `ServeHTTP` (lines 56-74). After the regex substitution produces a new path, the middleware forwards it to the backend without checking whether the path normalizes differently - unlike StripPrefix which rejects such paths with HTTP 400 after the CVE-2026-48020 fix.**Attack flow:**Attacker sends `GET /api../admin``sanitizePath` passes it unchanged (`api..` is a valid segment name, not a dot-segment)Router matches `PathPrefix(/api)` → selects the public router (no auth middleware)ReplacePathRegex applies `^/api(.*)` → captures `../admin` → replacement produces `/../admin`No normalization check exists → path forwarded to backend as-isBackend framework (Express, Flask, Django, Spring, ASP.NET) normalizes `/../admin` to `/admin`Attacker receives protected content without authentication**Suggested fix:** Add the same JoinPath equality check after line 67:PoC**Prerequisites:** Docker Engine 20.10+, Docker Compose v2, curl**1. Create `docker-compose.yml`:****2. Create `dynamic.yml`:****3. Create `server.js`:****4. Run and exploit:****Configuration note:** The regex `^/api(.*)` (without slash separator before the capture group) is the exploitable pattern. This is the natural way to write a prefix-strip equivalent with ReplacePathRegex and is functionally identical to `StripPrefix("/api")` for legitimate traffic. The pattern `^/api/(.*)` (with mandatory slash) is not exploitable - the same structural narrowing as CVE-2026-48020 where `StripPrefix("/api")` was vulnerable but `StripPrefix("/api/")` was not.ImpactAuthentication bypass. Any route protected by auth middleware on a separate router (BasicAuth, ForwardAuth, DigestAuth) can be accessed without credentials by an unauthenticated network attacker via a single HTTP request. Both read and write operations (GET/POST/PUT/DELETE) bypass authentication. The vulnerability affects deployments using ReplacePathRegex for prefix stripping - a common, documented configuration pattern.
CVSS v3.1 score: 9.1