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

CVE-2026-84378: HTTPX2 Python Client DoS Vulnerability

CVE-2026-84378 is a denial of service vulnerability in HTTPX2 Python HTTP client caused by inefficient SSE parsing that allows excessive CPU consumption. This post covers technical details, affected versions, and mitigation.

Published:

CVE-2026-84378 Overview

CVE-2026-84378 is an algorithmic complexity vulnerability in HTTPX2, a next generation HTTP client for Python. The flaw resides in the Server-Sent Events (SSE) parser located in src/httpx2/httpx2/_sse.py. The _SSELineDecoder.decode() method repeatedly copies and rescans buffered text when an SSE endpoint splits an unterminated line across many response chunks. Processing work grows quadratically with line length, allowing a crafted stream to exhaust CPU and stall a synchronous worker or asynchronous event loop. The issue affects HTTPX2 versions 2.5.0 through 2.9.x and is fixed in version 2.10.0.

Critical Impact

A malicious or compromised SSE endpoint can block synchronous workers or async event loops in applications using httpx2.Client.sse() or httpx2.AsyncClient.sse(), causing denial of service.

Affected Products

  • HTTPX2 for Python, versions 2.5.0 through 2.9.x
  • Applications using httpx2.Client.sse() for synchronous SSE consumption
  • Applications using httpx2.AsyncClient.sse() for asynchronous SSE consumption

Discovery Timeline

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

Technical Details for CVE-2026-84378

Vulnerability Analysis

The vulnerability is an algorithmic complexity flaw [CWE-407] in the SSE line decoder. When HTTPX2 consumes an SSE stream, incoming chunks are appended to an internal buffer and scanned for line terminators. In vulnerable versions, _SSELineDecoder.decode() re-encodes and rescans the entire buffered pending text on every incoming chunk. If the server never sends a newline, each new chunk triggers a full pass over all previously buffered data.

The total work performed to buffer a line of length N grows on the order of N², rather than linearly. A remote server streaming a long unterminated line in small pieces can drive CPU utilization to saturation. In synchronous deployments, the worker thread blocks. In asynchronous deployments, the event loop stalls, preventing other coroutines from running.

Root Cause

The root cause is repeated re-scanning and re-encoding of buffered SSE data. The pre-patch implementation invoked pending.encode("utf-8") and evaluated len(...) on the full pending string every time check_pending was called. This produced quadratic behavior as the buffer accumulated. The fix, introduced in pull request #1117 and released in version 2.10.0, tracks the pending byte size as an integer counter rather than recomputing it from the string on each iteration.

Attack Vector

Exploitation requires a client application to connect to an attacker-controlled or compromised SSE endpoint using sse() on httpx2.Client or httpx2.AsyncClient. The attacker returns a valid SSE response but delays the terminating newline while streaming many small chunks that extend a single line. No authentication or user interaction is required on the vulnerable client side.

python
         return None
 
-    def check_pending(self, pending: str) -> None:
+    def check_pending(self, pending_size: int) -> None:
         """
         Bound the total bytes buffered for the in-progress event, including
         a trailing line that has not been terminated by a newline yet.
         """
-        self._check_size(len(pending.encode("utf-8")))
+        self._check_size(pending_size)
 
     def _check_size(self, pending_size: int = 0) -> None:
         if self._max_event_size is not None and self._event_size + pending_size > self._max_event_size:

Source: GitHub Commit cbfc0e0. The patch replaces repeated pending.encode("utf-8") and len(...) calls with a pre-computed integer size, eliminating the quadratic scan.

Detection Methods for CVE-2026-84378

Indicators of Compromise

  • Sustained high CPU consumption in Python processes that consume SSE streams via HTTPX2.
  • Async event loop lag or synchronous worker starvation coinciding with outbound connections to SSE endpoints.
  • Long-lived HTTP responses with Content-Type: text/event-stream that transfer many small chunks without newline characters.
  • Application timeouts or health-check failures on services that call httpx2.Client.sse() or httpx2.AsyncClient.sse().

Detection Strategies

  • Inventory Python dependencies using SBOM tooling to identify HTTPX2 versions between 2.5.0 and 2.9.x.
  • Instrument SSE consumers with per-chunk timing metrics to flag disproportionate parser latency relative to bytes received.
  • Alert on outbound SSE connections that exceed configured maximum event size or duration thresholds.

Monitoring Recommendations

  • Monitor CPU time per SSE connection and set alerts on sustained single-core saturation in worker processes.
  • Track outbound connections to untrusted SSE endpoints and correlate with process resource metrics.
  • Log HTTPX2 version at application startup to detect drift from patched baselines across the fleet.

How to Mitigate CVE-2026-84378

Immediate Actions Required

  • Upgrade HTTPX2 to version 2.10.0 or later in all Python environments consuming SSE streams.
  • Audit application code for calls to httpx2.Client.sse() and httpx2.AsyncClient.sse() and validate the trust level of connected endpoints.
  • Restrict SSE consumers to allowlisted, trusted origins where possible.

Patch Information

The fix is available in HTTPX2 Release v2.10.0. Technical details are documented in GitHub Security Advisory GHSA-f2fp-rgf2-35cp, with implementation history in Pull Request #1071 and Pull Request #1117.

Workarounds

  • Set a conservative max_event_size on SSE clients to bound buffered bytes per event.
  • Enforce request and read timeouts on SSE calls to terminate stalled streams before CPU exhaustion propagates.
  • Isolate SSE consumers in dedicated worker processes so that a stalled parser cannot degrade unrelated application paths.
  • Deploy an egress proxy that enforces line-length and chunk-cadence limits on text/event-stream responses.
bash
# Upgrade HTTPX2 to the patched release
pip install --upgrade 'httpx2>=2.10.0'

# Verify installed version
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.