Sep 11, 2026·6 min read·25 visits
Unauthenticated remote attackers can bypass Traefik security middlewares by upgrading a connection to cleartext HTTP/2 (h2c) over an unrestricted route, establishing a raw TCP tunnel directly to the backend that allows uninspected multiplexed streams to reach private paths.
An architectural flaw in the Traefik reverse proxy allows unauthenticated remote attackers to bypass security middlewares (such as basic authentication, IP allowlists, and forward authorization) by initiating an unencrypted HTTP/2 (h2c) upgrade request, causing the proxy to transition the connection into an opaque bi-directional TCP tunnel.
CVE-2026-88008 represents an architectural security flaw within Traefik, an industry-standard cloud-native HTTP reverse proxy and load balancer. The vulnerability centers on the handling of unencrypted HTTP/2 connection upgrades, commonly known as h2c. When configured to route traffic to backends that support these cleartext upgrades, Traefik exposes an attack surface that allows unauthenticated network clients to establish an unmonitored communication path.
The core of the exposure resides in how Traefik manages connection-state transitions. When a client requests a protocol transition over an unrestricted endpoint, the proxy permits the negotiation to pass down to the service layer. This behavior ultimately shifts the proxy out of its role as an application-layer policy enforcement point, converting the session into a transport-layer pipe.
The operational impact of this behavior is authorization bypass. Attackers exploit this behavior to transmit subsequent HTTP payloads directly to restricted backend routes, bypassing critical gateway security policies such as BasicAuth, ForwardAuth, IPAllowList, and rate limits. Because the proxy is blind to the encapsulated traffic, the downstream application processes unauthorized administrative operations as authenticated commands.
The underlying security flaw stems from an inconsistency in protocol interpretation between the edge proxy and the backend application server. According to the HTTP/2 specification (RFC 7540, Section 3.2), cleartext connection upgrades require a specific negotiation handshake. A client issues an HTTP/1.1 request containing Upgrade: h2c, a Connection: Upgrade, HTTP2-Settings header, and a base64-encoded HTTP2-Settings payload.
In Go-based applications utilizing the standard library's net/http/httputil package, the ReverseProxy implementation acts as a hop-by-hop forwarder. Historically, this component forwarded the upgrade headers directly to the backend destination instead of terminating or properly validating them. When the backend service accepts the transition, it issues an HTTP 101 Switching Protocols response.
Upon detecting the 101 status code, the standard library ReverseProxy transitions the network connection from structured HTTP request parsing into an opaque, bi-directional TCP tunnel. From this point forward, the proxy ceases all application-layer inspection of the data stream. It assumes the negotiation established a dedicated channel and simply copies raw bytes back and forth between client and server, failing to apply any route parsing, middleware analysis, or path-based access control filters.
To address this vulnerability, the Traefik development team introduced a dedicated middleware component named h2cUpgradeHandler within the proxy service chain. This handler intercepts all incoming HTTP/1.1 requests prior to forwarding them to the reverse proxy engine, inspecting and neutralizing the hazardous connection headers.
The logic within pkg/server/service/upgrade.go relies on the golang.org/x/net/http/httpguts utility library to inspect connection tokens safely. Below is the implemented fix:
package service
import (
"net/http"
"golang.org/x/net/http/httpguts"
)
// h2cUpgradeHandler removes a client-initiated h2c upgrade before the request reaches the reverse proxy.
// This is a temporary workaround for httputil.ReverseProxy, which forwards the token.
type h2cUpgradeHandler struct {
next http.Handler
}
func newH2CUpgradeHandler(next http.Handler) http.Handler {
return &h2cUpgradeHandler{next: next}
}
func (h *h2cUpgradeHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if httpguts.HeaderValuesContainsToken(req.Header["Connection"], "Upgrade") &&
httpguts.HeaderValuesContainsToken([]string{req.Header.Get("Upgrade")}, "h2c") {
// Stripping the Upgrade header prevents the reverse proxy from entering a TCP tunnel state
delete(req.Header, "Upgrade")
}
// HTTP2-Settings header is also connection-specific and must not be forwarded
delete(req.Header, "Http2-Settings")
h.next.ServeHTTP(rw, req)
}By deleting the Upgrade header during the evaluation phase, the reverse proxy engine no longer computes an upgrade type. Consequently, the proxy strips the Connection header and routes the message as a standard HTTP/1.1 transaction. The backend never receives the upgrade trigger, preventing connection hijacking and establishing complete policy enforcement over the request life cycle.
Exploiting CVE-2026-88008 requires three distinct phases: locating an unrestricted path, sending the upgrade payload, and transmitting multiplexed HTTP/2 frames. The attack requires no authentication credentials and can be executed remotely if the backend supports cleartext HTTP/2 transitions.
First, the attacker identifies a public endpoint (e.g., /public/assets/logo.png) that is not protected by middleware filters like BasicAuth or IPAllowList. The attacker sends a crafted HTTP/1.1 request targeting this route, embedding the h2c upgrade headers. This request transits through Traefik, which validates the path as public, processes no blocking middleware, and forwards the packet directly to the backend.
GET /public/assets/logo.png HTTP/1.1
Host: target.local
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: AAMAAABkAAQAAP__If the backend accepts the upgrade, it responds with status 101 Switching Protocols. Traefik routes this response back to the client and immediately transitions the connection into a raw TCP tunnel. The attacker now switches their client socket to speak HTTP/2, sending multiplexed frames targeting protected paths like /admin/settings or /api/keys. Because Traefik only monitors the connection at the transport layer, the backend processes these multiplexed requests without Traefik's security layers intercepting them.
The interaction flow between the unauthenticated attacker, the Traefik proxy instance, and the backend application highlights how the security context changes after the HTTP 101 state transition.
This architecture shows how subsequent requests bypass security boundaries. Once the connection shifts state, authorization decisions previously enforced at the perimeter are completely negated.
The primary remediation strategy is to upgrade Traefik instances to patch versions 2.11.57 or 3.7.13. These versions natively incorporate the h2cUpgradeHandler to dismantle upgrade requests at the proxy entry point, preventing the establishment of the unauthenticated TCP tunnel.
For environments where immediate platform upgrades are not feasible, network administrators must deploy backend-level configuration modifications. Disabling cleartext HTTP/2 (h2c) support on backend application servers effectively neutralizes the attack surface. If the backend refuses to transition protocol states, it returns a standard HTTP/1.1 response status, maintaining normal proxy inspection.
Additionally, if cleartext HTTP/2 communication between Traefik and its backend service layers is necessary, administrators should use HTTP/2 with prior knowledge. By modifying the backend server scheme definition to h2c:// in Traefik's dynamic configuration, the system initiates HTTP/2 traffic directly. This avoids the HTTP/1.1 upgrade sequence entirely, ensuring the proxy remains in control of stream allocation and routing security.
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Traefik Traefik | >= 2.11.26, < 2.11.57 | 2.11.57 |
Traefik Traefik | >= 3.4.2, < 3.7.13 | 3.7.13 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-444 / CWE-863 |
| Attack Vector | Network (N) |
| CVSS v4.0 Score | 7.0 (High) |
| EPSS Score | 0.00 (Pending) |
| Impact | Authentication & Middleware Policy Bypass |
| Exploit Status | Proof-of-Concept State |
| CISA KEV Status | Not Listed |
The proxy and the backend interpret the sequence of stream/protocol state transitions differently, allowing downstream multiplexed traffic to bypass proxy-level controls.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.