CVE-2026-88009: Traefik: Rootless HTTP/1 request-target routes as "/" but is forwarded verbatim, bypassing path-scoped routing, middleware guards and access logging
Traefik accepts an HTTP/1.x request whose request-target is in rootless / opaque form (for example GET http:http://internal-vhost/admin HTTP/1.1). Go parses this into URL.Opaque with an empty URL.Path, so Traefik evaluates all routing, path-sanitization, middleware and access-log decisions against a path that normalizes to /, while the proxy forwards the attacker’s original target byte-for-byte to the backend. Router path/prefix guards, forwardAuth path-scoped policies and the encodedCharacters hardening never see the real target, and the access log records every such request as GET / HTTP/1.1. Against a backend that resolves a rootless target as a path, this yields cross-vhost routing bypass, path-scoped authorization bypass and access-log evasion — unauthenticated, with stock entrypoint defaults.
Traefik v3.0 through v3.6 are end-of-life and are also affected; they will not receive a fix on their own line. Users on those versions must upgrade to v3.7.13.
The scanner claims rewriteRequestBuilder (pkg/proxy/httputil/proxy.go:97) rebuilds the outbound target from URL.Path / RawPath / RawQuery but never clears URL.Opaque, so a client sending a rootless request-target (GET http:http://internal-vhost/admin HTTP/1.1) has that byte string written verbatim into the backend request line while Traefik routes, sanitizes, guards and logs an empty path.
The claim is correct in every load-bearing detail, and it reproduces end to end on the GA image traefik:v3.7 (v3.7.9, go1.26.5) with stock entrypoint defaults. Three separate consequences were observed on the wire, not inferred:
- Cross-vhost routing bypass. Traefik matched
Host(app.example.com), nginx served theinternal-vhostserver block. - Path-scoped authorization bypass. A
forwardAuthguard that denies^/adminreturnedDENYfor/adminandALLOWfor the opaque form of the same request, which then reached/adminon the backend. - Access-log evasion. All three requests, benign and malicious, were logged identically as
"GET / HTTP/1.1".
Plus a fourth that is decisive against the usual closure argument: the documented opt-in hardening encodedCharacters.allowEncodedSlash=false rejects the canonical /admin%2f..%2fsecret with 400, and does not fire at all on the opaque form carrying the identical payload.
This is not the “the operator left an opt-in permissive” shape that lesson L-012 and guideline G-03 teach us to decline. The hardening is enabled and is structurally bypassed.
References
- github.com/advisories/GHSA-f52w-8j3h-j724
- github.com/traefik/traefik/commit/58d1e9ca204526823211e30fd4634101c59d58e9
- github.com/traefik/traefik/pull/13796
- github.com/traefik/traefik/releases/tag/v2.11.57
- github.com/traefik/traefik/releases/tag/v3.7.13
- github.com/traefik/traefik/security/advisories/GHSA-f52w-8j3h-j724
- nvd.nist.gov/vuln/detail/CVE-2026-88009
Code Behaviors & Features
Detect and mitigate CVE-2026-88009 with GitLab Dependency Scanning
Secure your software supply chain by verifying that all open source dependencies used in your projects contain no disclosed vulnerabilities. Learn more about Dependency Scanning →