Skip to main content
Vulnerability Database/CVE-2026-84380

CVE-2026-84380: HTTPX2 Python Client Request Smuggling Flaw

CVE-2026-84380 is a request smuggling flaw in HTTPX2 Python HTTP client caused by improper header handling that allows both Content-Length and Transfer-Encoding headers. This post covers technical details, affected versions, impact, and mitigation steps.

Published:

CVE-2026-84380 Overview

CVE-2026-84380 affects HTTPX2, a next-generation HTTP client for Python maintained by Pydantic. The vulnerability exists in Request._prepare() within src/httpx2/httpx2/_models.py prior to version 2.11.0. The client adds a body-derived Content-Length header even when the caller already supplied a Transfer-Encoding header. This produces HTTP/1.1 requests carrying both framing headers, enabling request smuggling or connection desynchronization when downstream intermediaries disagree on precedence. The flaw is classified under CWE-444: Inconsistent Interpretation of HTTP Requests.

Critical Impact

Attackers positioned behind a shared proxy can smuggle requests, poison connections, or bypass front-end security controls when applications use HTTPX2 with caller-supplied Transfer-Encoding headers.

Affected Products

  • Pydantic HTTPX2 versions prior to 2.11.0
  • Python applications using HTTPX2 for outbound HTTP/1.1 requests
  • Deployments where HTTPX2 traffic transits intermediaries such as proxies, load balancers, or WAFs

Discovery Timeline

  • 2026-09-02 - CVE-2026-84380 published to NVD
  • 2026-09-02 - Last updated in NVD database

Technical Details for CVE-2026-84380

Vulnerability Analysis

HTTPX2 constructs outbound HTTP/1.1 requests by merging caller-supplied headers with a set of default framing headers. The Request._prepare() method iterates over defaults and calls setdefault() for each entry independently. This treats Content-Length and Transfer-Encoding as unrelated headers instead of mutually exclusive framing directives defined by RFC 7230.

When a caller explicitly sets Transfer-Encoding: chunked, HTTPX2 still appends a body-derived Content-Length computed from fixed-size byte, JSON, form, or known-length multipart bodies. The resulting request contains both headers on the wire. Front-end and back-end HTTP servers frequently disagree on which header takes precedence, and that disagreement is the primitive that enables HTTP request smuggling.

Root Cause

The defect is a header-processing logic error. The pre-patch code only skipped the default Transfer-Encoding when the request already carried an explicit Content-Length. It did not perform the symmetric check: skip the default Content-Length when the request already carried an explicit Transfer-Encoding. Because the two headers are mutually exclusive for HTTP/1.1 message framing, treating them independently allowed both to co-exist on the same request.

Attack Vector

Exploitation requires an application that forwards or accepts attacker-influenced Transfer-Encoding values into HTTPX2 requests, or that itself sends chunked requests through a shared intermediary. Once the malformed request reaches a proxy chain, differential parsing between the front-end and back-end lets an attacker prepend or append bytes to another user's request. Consequences include cache poisoning, credential capture via response queue desync, and bypass of front-end access controls.

python
    def _prepare(self, default_headers: dict[str, str]) -> None:
        for key, value in default_headers.items():
-            # Ignore Transfer-Encoding if the Content-Length has been set explicitly.
+            # Ignore Content-Length if Transfer-Encoding has been set explicitly.
+            if key.lower() == "content-length" and "Transfer-Encoding" in self.headers:
+                continue
+            # Ignore Transfer-Encoding if Content-Length has been set explicitly.
            if key.lower() == "transfer-encoding" and "Content-Length" in self.headers:
                continue
            self.headers.setdefault(key, value)

Source: GitHub Commit 829b93a — patch that adds the symmetric check ensuring the two framing headers are treated as mutually exclusive.

Detection Methods for CVE-2026-84380

Indicators of Compromise

  • Outbound HTTP/1.1 requests originating from Python services that contain both Content-Length and Transfer-Encoding: chunked headers.
  • Proxy or WAF logs recording 400-class framing errors, unexpected connection resets, or requests flagged as malformed when originating from services using HTTPX2.
  • Unexplained cross-user response mixing, cache poisoning entries, or access-control bypass events on services fronted by a shared proxy.

Detection Strategies

  • Software composition analysis for httpx2 < 2.11.0 across Python build manifests, container images, and lockfiles.
  • Inspect outbound traffic at the egress proxy for requests containing both framing headers; flag any HTTP/1.1 message that presents both Content-Length and Transfer-Encoding.
  • Fuzz internal HTTP clients with chunked bodies and confirm downstream intermediaries reject dual-framing requests rather than forwarding them.

Monitoring Recommendations

  • Alert on WAF or reverse-proxy rules that flag HTTP request smuggling signatures on paths served by HTTPX2 clients.
  • Track version drift for the HTTPX2 dependency in production build pipelines and fail builds that resolve versions below 2.11.0.
  • Correlate anomalous response-body sizes and unexpected Connection: close events with source services identified as HTTPX2 consumers.

How to Mitigate CVE-2026-84380

Immediate Actions Required

  • Upgrade HTTPX2 to version 2.11.0 or later in every affected service and rebuild dependent container images.
  • Audit application code for call sites that set Transfer-Encoding explicitly and validate the resulting request headers on a test proxy.
  • Enforce strict HTTP parsing on intermediaries so that requests containing both Content-Length and Transfer-Encoding are rejected rather than forwarded.

Patch Information

The fix is included in HTTPX2 version 2.11.0. The patch in Request._prepare() adds a symmetric check that skips the default Content-Length when the request already contains a Transfer-Encoding header, restoring mutual exclusivity between the two framing headers. See GitHub Pull Request #1137, the GitHub Release v2.11.0, and the GitHub Security Advisory GHSA-pf96-p4fj-6566.

Workarounds

  • Remove caller-supplied Transfer-Encoding headers before invoking HTTPX2 request methods and let the client compute framing from the body.
  • Route HTTPX2 traffic exclusively over HTTP/2 endpoints where message framing is length-prefixed and immune to CL.TE style desync.
  • Deploy a reverse proxy in front of downstream services configured to reject any HTTP/1.1 request containing both framing headers.
bash
# Pin HTTPX2 to the fixed version in requirements.txt
httpx2>=2.11.0

# Verify the resolved version in a running environment
python -c "import httpx2; print(httpx2.__version__)"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.