GHSA-pf96-p4fj-6566: Medium severity pip/httpx2 vulnerability
Summary
HTTPX2 can automatically add a Content-Length header to a request that already contains a caller-supplied Transfer-Encoding header. The resulting HTTP/1.1 request contains both framing headers, which can create an ambiguous message boundary and enable request smuggling or connection desynchronization when processed by intermediaries that disagree about which header takes precedence.
Details
When a request body has a known size, HTTPX2's content encoder returns a default Content-Length. Request.prepare() applies each default header with setdefault(), which only checks whether that same header is already present. It does not check whether the mutually exclusive Transfer-Encoding header is present.
For example:
python import httpx2
request = httpx2.Request( "POST", "http://example.com/", headers={"Transfer-Encoding": "chunked"}, content=b"test 123", )
print(request.headers)
The request contains both:
text Transfer-Encoding: chunked Content-Length: 8
On an HTTP/1.1 connection, the body is serialized using chunked transfer coding while both headers are sent on the wire. This violates HTTP message-framing requirements. Fixed-size byte, JSON, form, and known-length multipart bodies can reach the affected path.
Streaming bodies with an explicit Content-Length are not affected in current HTTPX2 releases because the automatically generated Transfer-Encoding is already suppressed in that direction.
Impact
An attacker may be able to use the conflicting framing headers as a request-smuggling or desynchronization primitive. Exploitation requires an application to pass attacker-controlled request framing headers and associated body data to HTTPX2, use HTTP/1.1, and communicate through a proxy or origin that accepts conflicting headers and interprets them differently from another hop.
Depending on the downstream infrastructure, successful exploitation could interfere with requests sharing a persistent connection, bypass front-end routing or authorization decisions, or poison responses or caches. Applications that do not forward attacker-controlled Transfer-Encoding headers are not directly exposed.
Mitigation
Upgrade to HTTPX2 2.11.0 or later. Patched versions treat Content-Length and Transfer-Encoding as mutually exclusive when applying automatically generated request headers.
If upgrading is not immediately possible, remove Transfer-Encoding and other hop-by-hop framing headers from untrusted input before constructing outbound requests. Applications acting as proxies should derive outbound framing from the body rather than forwarding inbound Content-Length or Transfer-Encoding headers.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/httpx2to a version that resolves this vulnerability.Fixed in 2.11.0 - Upgrade
Upgrade
httpx2to a version that resolves this vulnerability.Fixed in 2.11.0 - Configuration
If upgrading is not immediately possible, remove 'Transfer-Encoding' and other hop-by-hop framing headers from untrusted input before constructing outbound requests, so applications do not forward conflicting inbound request framing headers. (Material notes HTTPX2 can add a 'Content-Length' when a caller-supplied 'Transfer-Encoding' header is present.)
HTTPX2 (outbound request construction via proxies/origins) Transfer-Encoding / hop-by-hop framing headers handling = Remove attacker-controlled 'Transfer-Encoding' (and other hop-by-hop framing headers) from untrusted input before constructing outbound requests
Event History
Frequently Asked Questions
Which applications are exposed to this behavior?
Applications that construct HTTPX2 requests with a caller-supplied Transfer-Encoding header and a body whose size is known, such as fixed-size byte or JSON content, can produce requests containing both Transfer-Encoding and Content-Length. The issue is relevant when those requests use HTTP/1.1 and pass through intermediaries that interpret the two framing headers differently.
Does this occur with ordinary requests that do not set Transfer-Encoding?
The described condition requires a caller-supplied Transfer-Encoding header. HTTPX2 adds Content-Length when the body size is known, but the conflict arises because it does not check for Transfer-Encoding before adding that default header.
What can be done before an update is available?
Do not supply Transfer-Encoding on requests with known-size bodies. Ensure generated HTTP/1.1 requests contain only one message-framing mechanism rather than both Transfer-Encoding and Content-Length.
How can I determine whether my application is affected?
Review request-building code for explicit Transfer-Encoding headers, especially on POST or other requests carrying fixed-size content. Inspect the resulting request headers or HTTP/1.1 wire output for the simultaneous presence of Transfer-Encoding: chunked and Content-Length.