CVE-2026-73548 Overview
CVE-2026-73548 is an HTTP request smuggling vulnerability [CWE-444] in the Envoy proxy that enables cross-client response leakage. Envoy forwards data for a configured non-WebSocket HTTP upgrade before the upstream accepts the upgrade. An unauthenticated HTTP/2 client can place a complete HTTP/1.1 request inside extended CONNECT data. Envoy downgrades the request, writes the data unframed to a keep-alive HTTP/1.1 upstream, and returns the socket to the shared pool while the smuggled response remains queued. A different downstream client can then receive the attacker's response.
Critical Impact
Unauthenticated attackers can poison shared upstream connections and cause responses intended for one client to be delivered to another, exposing sensitive session data.
Affected Products
- Envoy proxy versions prior to 1.36.10
- Envoy proxy versions prior to 1.37.6 and 1.38.4
- Envoy proxy versions prior to 1.39.1
Discovery Timeline
- 2026-09-21 - CVE-2026-73548 published to the National Vulnerability Database (NVD)
- 2026-09-23 - Last updated in NVD database
Technical Details for CVE-2026-73548
Vulnerability Analysis
The flaw is a classic HTTP request smuggling condition triggered through Envoy's generic (non-WebSocket) HTTP upgrade path. When an HTTP/2 client issues an extended CONNECT frame requesting a protocol upgrade, Envoy translates the request into an HTTP/1.1 upgrade toward the upstream. The proxy immediately forwards any accompanying payload to the upstream socket before receiving the upstream's 101 Switching Protocols confirmation.
If the payload contains a well-formed HTTP/1.1 request, the upstream parses it as a pipelined second request on the shared keep-alive connection. Envoy, unaware that a second response is now queued, returns the socket to its shared connection pool. The next downstream client assigned that pooled connection receives the smuggled response, breaking the confidentiality boundary between tenants.
Root Cause
The root cause lies in premature payload forwarding during upgrade negotiation. Envoy did not gate generic upgrade body data on upstream acceptance of the upgrade. The upstream codec filter lacked a pausedForGenericUpgrade state, so attacker-controlled bytes reached the upstream before Envoy could verify the upgrade succeeded.
Attack Vector
An unauthenticated remote attacker sends an HTTP/2 extended CONNECT with a non-WebSocket protocol and pipelines a full HTTP/1.1 request as CONNECT data. Envoy writes the smuggled request unframed to a keep-alive HTTP/1.1 upstream. The upstream generates a response that is queued on the shared connection and later delivered to an unrelated downstream client. WebSocket upgrades, plain CONNECT, disabled backend keep-alive, per-downstream pools, and max_requests_per_connection set to 1 are not affected.
// Patch: envoy/http/filter.h - new state to pause generic upgrade body
virtual bool pausedForWebsocketUpgrade() const PURE;
virtual void setPausedForWebsocketUpgrade(bool value) PURE;
+ // Setters and getters to determine if sending body payload is paused on
+ // confirmation of a generic (non-WebSocket) HTTP upgrade. These should only be used by the
+ // upstream codec filter.
+ virtual bool pausedForGenericUpgrade() const PURE;
+ virtual void setPausedForGenericUpgrade(bool value) PURE;
+
// Disable the route timeout after websocket upgrade completes successfully.
// This should only be used by the upstream codec filter.
virtual void disableRouteTimeoutForWebsocketUpgrade() PURE;
Source: Envoy commit 3098556269
Detection Methods for CVE-2026-73548
Indicators of Compromise
- HTTP/2 extended CONNECT frames carrying payload bytes that begin with an HTTP/1.1 request line (for example, GET / HTTP/1.1\r\nHost:).
- Upstream access logs showing more responses than requests attributed to a single downstream stream.
- Downstream clients receiving responses with Host headers or resource paths they never requested.
- Envoy running any version prior to 1.36.10, 1.37.6, 1.38.4, or 1.39.1 with generic HTTP upgrades enabled.
Detection Strategies
- Inspect HTTP/2 upgrade traffic for extended CONNECT frames whose body payload parses as a syntactically valid HTTP/1.1 request.
- Correlate downstream request identifiers with upstream response identifiers to detect mismatches indicative of pooled-connection response bleed.
- Alert on Envoy configurations that combine generic (non-WebSocket) upgrades with shared upstream connection pools and keep-alive.
Monitoring Recommendations
- Enable Envoy access logging with request and response identifiers, then centralize logs for correlation and anomaly detection.
- Track the upstream_cx_pool_overflow and per-cluster keep-alive counters to baseline pool reuse behavior.
- Monitor for sudden increases in HTTP/2 extended CONNECT traffic from previously idle clients.
How to Mitigate CVE-2026-73548
Immediate Actions Required
- Upgrade Envoy to 1.36.10, 1.37.6, 1.38.4, or 1.39.1 as soon as possible.
- Audit listener and cluster configurations for generic HTTP upgrade routes and restrict them to trusted clients where feasible.
- Review upstream access logs for signs of pooled-connection response mismatches during the exposure window.
Patch Information
The fix is delivered in Envoy releases v1.36.10, v1.37.6, v1.38.4, and v1.39.1. Generic upgrade payload is now paused until the upstream accepts the upgrade. Full advisory details are available in GitHub Security Advisory GHSA-3vhp-c83q-jqc2.
Workarounds
- Set max_requests_per_connection to 1 on affected upstream clusters to prevent connection reuse.
- Disable backend keep-alive for clusters that terminate generic HTTP upgrades.
- Use per-downstream connection pools instead of shared pools for sensitive upstream services.
- Restrict listeners to WebSocket-only upgrades or plain CONNECT where generic upgrades are not required.
# Ensure the reloadable feature that enforces the fix remains enabled (default: true)
--runtime-feature-override-for-tests envoy.reloadable_features.http_pause_generic_upgrade_request_body=true
# Defense-in-depth: disable upstream connection reuse for affected clusters
# clusters:
# - name: upstream_cluster
# max_requests_per_connection: 1
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.
