Update dependency httpx2 to v2.12.0 [SECURITY] - #84
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
2.9.1→2.12.0HTTPX2: Secure WebSocket traffic sent without TLS through SOCKS proxies
CVE-2026-84381 / GHSA-7mj9-2mp8-4m2p
More information
Details
Summary
httpcore2 does not start TLS for
wss://connections routed through a SOCKS5 proxy. The WebSocket opening handshake and all subsequent frames are sent in plaintext through the proxy path, despite the caller selecting the securewssscheme.The transport flaw affects httpcore2 releases before
2.10.0. HTTPX2 exposed this behavior through its publicClient.websocket()andAsyncClient.websocket()APIs from2.6.0through2.9.1.Details
The synchronous and asynchronous SOCKS5 connection implementations upgrade the established proxy tunnel to TLS only when the remote origin scheme is
https. The equivalent check does not includewss. After the SOCKS5 handshake succeeds, the raw stream is therefore passed directly to the HTTP/1.1 connection, which writes the WebSocket upgrade request without first performing a TLS handshake or verifying the destination certificate.For example, an application using HTTPX2
2.6.0through2.9.1may open an authenticated WebSocket through a SOCKS proxy:On affected versions, the stream passing through the SOCKS proxy begins with a plaintext request such as:
Before HTTPX2
2.6.0, the same underlying httpcore2 behavior could be reached by integrations constructing a WebSocket upgrade request through the low-level transport API, but HTTPX2 did not yet provide its native WebSocket client API.A normal secure WebSocket server will usually reject these plaintext bytes because it expects a TLS ClientHello. However, a malicious or compromised SOCKS proxy can accept the SOCKS connection, observe the plaintext handshake, return a forged
101 Switching Protocolsresponse, and then read or modify WebSocket frames in both directions. An observer between the proxy and destination may also read the plaintext traffic.RFC 6455 requires a client using a secure WebSocket connection to perform the TLS handshake before sending the WebSocket opening handshake. A
wssURI promises confidentiality, integrity, and endpoint authentication through TLS.Impact
An attacker able to control or observe the SOCKS proxy path can obtain URL query parameters, authorization headers, cookies, and application messages that the caller expected TLS to protect. Because no TLS handshake occurs, certificate verification also does not occur, allowing an attacker controlling the proxy to impersonate the WebSocket server and inject or alter messages.
Only
wss://connections routed through a SOCKS5 proxy are affected. Directwss://connections and ordinaryhttps://requests through SOCKS already start TLS correctly.Mitigation
Upgrade HTTPX2 and httpcore2 to
2.10.0or later. Patched versions start TLS for bothhttpsandwssorigins in the synchronous and asynchronous SOCKS5 connection paths.If upgrading is not immediately possible, do not route
wss://connections through a SOCKS proxy. Use a direct secure WebSocket connection or another transport that performs and verifies TLS to the WebSocket origin.Severity
CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
HTTPX2: Quadratic SSE line buffering can cause CPU denial of service
CVE-2026-84378 / GHSA-f2fp-rgf2-35cp
More information
Details
Summary
HTTPX2's Server-Sent Events (SSE) parser repeatedly copied and rescanned buffered text when a server split one unterminated line across many response chunks. The total work grows quadratically with the length of the line. An attacker-controlled or compromised SSE endpoint can exploit this behavior to consume excessive client CPU.
Details
Before version 2.10.0, HTTPX2 combined the complete pending SSE line with each newly received chunk and then scanned the combined text for line separators. If an SSE server sends a long line as many small chunks without a line separator, every chunk causes all previously received text to be copied and scanned again. For
nfixed-size chunks, this results in O(n²) processing.The behavior affects both
httpx2.Client.sse()andhttpx2.AsyncClient.sse(). Other response APIs do not use the SSE parsing path.Impact
Applications that consume SSE from an attacker-controlled or compromised endpoint can experience excessive CPU usage. A crafted stream can block a synchronous worker or the asynchronous event loop that is consuming it, degrading availability for other work in that process. Confidentiality and integrity are not affected.
Mitigation
Upgrade to HTTPX2 2.10.0 or later. SSE parsing now accumulates incomplete line fragments and combines them only when necessary, making processing linear in the amount of received data. HTTPX2 2.10.0 also limits buffered SSE events to 1 MiB by default through
max_event_size.If upgrading is not immediately possible, only consume SSE from trusted endpoints and enforce an external size or time budget on the stream.
Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
HTTPX2: Multipart part header injection via unvalidated file Content-Type and custom headers
CVE-2026-84379 / GHSA-h4x7-gw46-3wm6
More information
Details
Summary
HTTPX2 serializes the per-file
Content-Typeand custom headers supplied through thefiles=tuple API directly into themultipart/form-databody without validating custom header names or values. An attacker who can influence upload metadata passed to HTTPX2 can use CR or LF characters to terminate a multipart part header and inject additional part headers or end the part header block early.Details
The three-element file tuple accepts
(filename, content, content_type), and the four-element form accepts(filename, content, content_type, headers).FileField.render_headers()interpolates the supplied header names and values between CRLF delimiters without validating them.For example:
The generated body contains an attacker-injected part header:
The same issue affects names and values in the custom header mapping from the four-element tuple.
Field names and filenames are serialized through a separate escaping path and do not permit CRLF header injection.
Impact
Applications are affected when they pass attacker-controlled upload metadata into the per-file
content_typeor customheadersarguments. The receiving server interprets injected lines as genuine multipart part headers. Depending on how that server validates and processes uploads, this can alter part semantics or bypass checks based on part headers.This does not split the outer HTTP request: the injected headers are contained within the multipart body. The concrete security impact therefore depends on the downstream multipart parser and application behavior.
Mitigation
Upgrade to HTTPX2
2.11.0or later. Patched versions reject forbidden control characters in multipart part header names and values and raiseValueErrorbefore serializing the request.If upgrading is not immediately possible, applications should validate custom multipart header names as HTTP field-name tokens. They should reject NUL, CR, LF, other C0 controls except horizontal tab, and DEL in per-file content types and custom header values before passing them to HTTPX2.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
HTTPX2: Conflicting Content-Length and Transfer-Encoding headers can be auto-generated
CVE-2026-84380 / GHSA-pf96-p4fj-6566
More information
Details
Summary
HTTPX2 can automatically add a
Content-Lengthheader to a request that already contains a caller-suppliedTransfer-Encodingheader. 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 withsetdefault(), which only checks whether that same header is already present. It does not check whether the mutually exclusiveTransfer-Encodingheader is present.For example:
The request contains both:
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-Lengthare not affected in current HTTPX2 releases because the automatically generatedTransfer-Encodingis 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-Encodingheaders are not directly exposed.Mitigation
Upgrade to HTTPX2
2.11.0or later. Patched versions treatContent-LengthandTransfer-Encodingas mutually exclusive when applying automatically generated request headers.If upgrading is not immediately possible, remove
Transfer-Encodingand 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 inboundContent-LengthorTransfer-Encodingheaders.Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:LReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
HTTPX2: Streaming response decompression does not bound peak memory (decompression amplification)
CVE-2026-84382 / GHSA-8xx6-hgc6-gc2m
More information
Details
Summary
When decoding a compressed response body (
gzip,deflate,br, orzstd), HTTPX2 fully decompressed each network read before yielding content to the application. A small compressed input could therefore cause a large intermediate memory allocation, even when the application streamed the response to keep memory usage bounded.Details
HTTPX2's default transport reads the socket in pieces of up to 64 KiB. Before
2.12.0, each piece was inflated completely into one intermediate allocation before any decompressed bytes were yielded.At DEFLATE's maximum compression ratio of roughly 1032:1, a 64 KiB compressed chunk can expand to about 64 MiB in one allocation. Brotli and Zstandard responses can cause similarly large amplification. Streaming the response did not prevent these transient allocations.
Impact
Applications that fetch resources from untrusted or attacker-influenced servers - such as webhook receivers, link unfurlers, crawlers, SSRF-reachable fetchers, and redirect followers - can experience memory pressure or out-of-memory termination when processing a malicious compressed response. No authentication or user interaction is required beyond issuing a request to the server.
Mitigation
Upgrade to HTTPX2
2.12.0or later. Patched versions decompress responses incrementally with bounded intermediate buffers, including responses with multiple content encodings.Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Release Notes
pydantic/httpx2 (httpx2)
v2.12.0Compare Source
Highlights
🛡️ Bounded response decompression
httpx2now decodesgzip,deflate, Brotli, and Zstandard responses incrementally. Each decode step emits at most 1 MiB, so streaming a highly compressed response no longer requires materializing an entire inflated network chunk in memory (#1126).📦 Shared Zstandard API
Python 3.13 and earlier now use
backports.zstd, which provides the same bounded incremental decompression API ascompression.zstdon Python 3.14 and later (#1146).httpx2
Changed
backports.zstdfor Zstandard decoding on Python 3.13 and earlier by @Kludex in #1146Fixed
httpcore2
No changes since
2.11.0. Version bumped to stay in lockstep withhttpx2.Full Changelog: pydantic/httpx2@v2.11.0...v2.12.0
v2.11.0Compare Source
Highlights
🌐 Public origin API
httpx2now includes an immutable and hashableOriginvalue object, available throughURL.origin. It provides normalized scheme, host, and effective port comparisons without including URL paths, queries, fragments, or credentials (#1134).🛠️ Request compatibility and validation
Transfer-Encodingheaders now take precedence over body-derivedContent-Lengthheaders (#1137).httpx2
Added
Originvalue object andURL.originproperty by @Kludex in #1134Changed
brotliextra by @Kludex in #1141Fixed
Transfer-Encodingheaders and expose buffered request body lengths to WSGI applications by @Kludex in #1137httpcore2
Changed
Full Changelog: pydantic/httpx2@v2.10.0...v2.11.0
v2.10.0Compare Source
Highlights
🚀 Performance and memory improvements
Set-Cookieheader, making typical requests roughly 8% faster (#1107).🕸️ WebAssembly / Emscripten support
httpx2now runs on Pyodide / Emscripten, using a JavaScriptfetch-based transport defined inhttpx2-jsfetch(#1119, #1114). Thanks @hoodmane!httpx2
Added
max_event_sizeto cap SSE event buffering by @Kludex in #1071Changed
Set-Cookieby @Kludex in #1107str | Noneinstead ofAnyfromHeaders.getby @ItsDrike in #1121Fixed
httpcore2
Added
Changed
Fixed
KeyErrorwhen an HTTP/2 stream fails by @yhay81 in #1093wssscheme in SOCKS5 proxy connections by @Kludex in #1104🙏 New Contributors
Full Changelog: pydantic/httpx2@v2.9.1...v2.10.0
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.