Skip to content

chore(deps): update dependency httpx2 to v2.12.0 [security] - #118

Merged
renovate[bot] merged 1 commit into
mainfrom
renovate/pypi-httpx2-vulnerability
Sep 9, 2026
Merged

chore(deps): update dependency httpx2 to v2.12.0 [security]#118
renovate[bot] merged 1 commit into
mainfrom
renovate/pypi-httpx2-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
httpx2 (changelog) 2.10.02.12.0 age confidence

Warning

Some dependencies could not be looked up. Check the Dependency Dashboard for more information.


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-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:

import httpx2

request = httpx2.Request(
    "POST",
    "http://example.com/",
    headers={"Transfer-Encoding": "chunked"},
    content=b"test 123",
)

print(request.headers)

The request contains both:

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.

Severity

  • CVSS Score: 5.6 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L

References

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-Type and custom headers supplied through the files= tuple API directly into the multipart/form-data body 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:

import httpx2

request = httpx2.Request(
    "POST",
    "https://example.com/upload",
    headers={"Content-Type": "multipart/form-data; boundary=BOUNDARY"},
    files={
        "file": (
            "safe.txt",
            b"payload",
            "text/plain\r\nX-Injected: true",
        )
    },
)

print(request.read().decode())

The generated body contains an attacker-injected part header:

--BOUNDARY
Content-Disposition: form-data; name="file"; filename="safe.txt"
Content-Type: text/plain
X-Injected: true

payload
--BOUNDARY--

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_type or custom headers arguments. 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.0 or later. Patched versions reject forbidden control characters in multipart part header names and values and raise ValueError before 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 Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

References

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, or zstd), 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.0 or later. Patched versions decompress responses incrementally with bounded intermediate buffers, including responses with multiple content encodings.

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

pydantic/httpx2 (httpx2)

v2.12.0

Compare Source

Highlights

🛡️ Bounded response decompression

httpx2 now decodes gzip, 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 as compression.zstd on Python 3.14 and later (#​1146).

httpx2

Changed
  • Use backports.zstd for Zstandard decoding on Python 3.13 and earlier by @​Kludex in #​1146
Fixed
  • Bound peak memory while streaming compressed responses and close response streams when decoding fails by @​Kludex in #​1126

httpcore2

No changes since 2.11.0. Version bumped to stay in lockstep with httpx2.

Full Changelog: pydantic/httpx2@v2.11.0...v2.12.0

v2.11.0

Compare Source

Highlights

🌐 Public origin API

httpx2 now includes an immutable and hashable Origin value object, available through URL.origin. It provides normalized scheme, host, and effective port comparisons without including URL paths, queries, fragments, or credentials (#​1134).

🛠️ Request compatibility and validation
  • Explicit Transfer-Encoding headers now take precedence over body-derived Content-Length headers (#​1137).
  • Deprecated status code aliases are available again (#​1135).
  • Multipart part headers are validated before serialization (#​1142).

httpx2

Added
Changed
Fixed
  • Restore deprecated status code aliases by @​Kludex in #​1135
  • Extract HTTP/2 release notes from changelog headings correctly by @​Kludex in #​1136
  • Respect explicit Transfer-Encoding headers and expose buffered request body lengths to WSGI applications by @​Kludex in #​1137
  • Validate multipart part header names and values before serialization by @​Kludex in #​1142

httpcore2

Changed
  • Cache sniffio availability instead of importing it on every synchronization call by @​mbeijen in #​1132

Full Changelog: pydantic/httpx2@v2.10.0...v2.11.0


Configuration

📅 Schedule: (in timezone Europe/Berlin)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Enabled.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate
renovate Bot requested a review from a team as a code owner September 8, 2026 22:47
@renovate renovate Bot added bot Automated pull requests or issues dependencies Pull requests that update a dependency file renovate Pull requests from Renovate skip:codecov Skip Codecov reporting and check labels Sep 8, 2026
@renovate
renovate Bot enabled auto-merge (squash) September 8, 2026 22:47
@sonarqubecloud

sonarqubecloud Bot commented Sep 8, 2026

Copy link
Copy Markdown

@codecov

codecov Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

@renovate
renovate Bot merged commit ecd4e0b into main Sep 9, 2026
16 checks passed
@renovate
renovate Bot deleted the renovate/pypi-httpx2-vulnerability branch September 9, 2026 02:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot Automated pull requests or issues dependencies Pull requests that update a dependency file renovate Pull requests from Renovate skip:codecov Skip Codecov reporting and check

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants