Urgent: Fix urllib3 CVE-2025-66471 Streaming Decompression DoS

  • Thread Author
A newly disclosed vulnerability in the widely used Python HTTP library urllib3 can let small, highly compressed responses force clients to decompress massive amounts of data — consuming CPU and memory and causing denial-of-service conditions for applications that stream HTTP responses. The issue, tracked as CVE-2025-66471, affects urllib3 releases from 1.0 up to (but not including) 2.6.0; a security fix is included in urllib3 v2.6.0 and subsequent maintenance releases. Immediate action is required for any service or application that uses urllib3 for streaming HTTP content, especially those that accept content from untrusted sources or perform on-the-fly decompression.

Tech infographic of gzip content-encoding flowing into memory with a CVE-2025-66471 badge.Background​

Python applications across the ecosystem — web frameworks, data ingestion pipelines, CI/CD runners, cloud agents, and CLIs — frequently rely on urllib3 for HTTP requests, connection pooling, and streaming large responses without loading them fully into memory. The library’s streaming API lets developers read response bodies in small chunks, reducing memory pressure and improving responsiveness when handling large uploads or downloads.
Streaming compressed content introduces complexity: when a server sends a compressed payload (Content-Encoding: gzip, deflate, br, zstd, etc., the client must read compressed bytes from the wire and decompress them until it has produced enough uncompressed data to meet a requested chunk size. The vulnerable behavior arises when the decompression logic is allowed to produce much more uncompressed data than requested — a classic decompression-bomb scenario where a tiny compressed payload expands to huge memory size. The result is excessive CPU and memory allocation on the client side even when the application only asked for a small chunk.

What went wrong: technical root cause​

At a high level, the flaw is an implementation detail in the streaming and decoding code paths of urllib3’s HTTPResponse and its ContentDecoder implementations.
  • Streaming contract vs. decompressor behavior. The streaming API exposes methods like stream, read(amt), read1(amt), read_chunked(amt), and readinto(b) that promise to return up to a requested amount of decompressed data per call. Internally, urllib3 feeds compressed bytes into a decompressor until it can provide the requested amount of decompressed output.
  • Decompression overshoot. For some decoder implementations and certain compression formats, feeding a small amount of compressed input may produce a disproportionately large amount of decompressed output. In the vulnerable code path, urllib3 could allow a single decompression operation to fully expand such an input, placing tens or hundreds of megabytes (or more) into an internal buffer even though the request asked for a small chunk.
  • Resource exhaustion (CWE-409). The upshot is predictable: a malicious server or a man-in-the-middle that controls response bodies can craft a compact compressed blob that decompresses to an enormous size. When an application streams that response, the client will attempt to hold the decompressed result — driving CPU and memory usage to dangerous levels and potentially crashing or severely degrading the host process.
This is not an exploit for data theft or code execution; the primary impact is availability — a denial-of-service vector against clients that process compressed streaming responses without safeguards.

Affected software and scope​

  • Affected urllib3 versions: all releases >= 1.0 and < 2.6.0 are impacted by this streaming decompression issue.
  • Patched version: upgrading to urllib3 v2.6.0 or later contains the fix. Subsequent maintenance releases (for example, v2.6.1) restore small API regressions and are recommended when available.
  • Affected APIs / methods: streaming-focused methods are explicitly implicated — stream, read(amt), read1(amt), read_chunked(amt), and readinto(b) when automatic decoding is enabled. Calls that preload the entire response (preload_content=True) still load content into memory, but the security problem specifically concerns on-demand decoding during streaming.
  • Decode types: the issue impacts standard content encodings commonly used on the web — gzip, deflate, and newer formats such as br (Brotli) and zstd depending on decoder implementations present in the environment.
  • Downstream ecosystems: any project that depends on vulnerable urllib3 versions is potentially at risk if it uses streaming/decompression behavior. That includes many Python libraries and services that rely on urllib3 directly or transitively (for example, HTTP client libraries, SDKs, scrapers, and agents). Bundled or vendorized copies of urllib3 in downstream projects must be checked and updated when necessary.

Severity and exploitability​

  • Primary impact: Availability — Denial-of-Service (resource exhaustion).
  • CVSS context (v4 metrics): The vulnerability scores high for availability impact and ease-of-exploitation characteristics typical for a network-exploitable DoS vector. The streaming API is commonly used without special privileges and requires no user interaction; an attacker-hosted server or poisoned response on a path controlled by an attacker is sufficient to trigger the condition.
  • Attacker model: A remote attacker that can control an HTTP response to the vulnerable client (for example, a controlled web service the client calls, a compromised CDN origin, or an on-path adversary) can mount the attack. Attack complexity is low; the attacker must simply return a deliberately crafted compressed blob.
  • No confidentiality or integrity loss: there is no evidence this defect enables data exfiltration or code execution. The primary risk is that services crash or become unavailable.

What was changed in the fix (high level)​

The upstream changes in the security patch for v2.6.0 focus on constraining decompression behavior and avoiding full expansion beyond requested thresholds:
  • Limits on decompression output per read. The patched implementation prevents decoders from producing arbitrarily large decompressed output in response to a single small input chunk; decoders are constrained to respect a max_length limit for decompression during streaming reads.
  • Safer decoder APIs. New or modified decoder helpers, including iterator-style decompression (for Brotli and others), reduce the risk of excessive buffering and needless copying of decoded data.
  • Chained-encoding protections. The fix also restricted the number of allowed chained encodings in the Content-Encoding header to avoid amplification by repeated layered decoders.
  • Brotli dependency guidance. Because Brotli decoders may be installed in the environment independently of urllib3 itself, the fix includes guidance to upgrade Brotli/brotlicffi/brotlipy packages to compatible patched versions to get the full protection.

Immediate mitigation and remediation steps​

For engineering and operations teams, the most reliable remedial action is to upgrade. If an immediate upgrade is impossible, follow the temporary mitigations below.
  • Upgrade to the fixed library
  • Use a package manager to upgrade to urllib3 >= 2.6.0 as soon as practicable:
  • pip: pip install --upgrade "urllib3>=2.6.0"
  • For pinned requirements, update requirements.txt or pyproject.toml and rebuild environments.
  • If your distribution packages urllib3 (system packages), track and install your OS vendor’s security updates.
  • If you cannot upgrade immediately, disable on-the-fly decoding for streaming reads
  • When calling urllib3 directly, avoid automatic decompression in streaming code:
  • Construct the request with preload_content=False and iterate the response with decoding disabled:
  • Example:
  • resp = http.request('GET', url, preload_content=False)
  • for chunk in resp.stream(65536, decode_content=False):
  • process(chunk)
  • Or call read(amt, decode_content=False) and explicitly handle decompression in a controlled way.
  • This prevents urllib3 from invoking potentially unsafe decoder codepaths during streaming; however, it places responsibility on the application to perform safe, bounded decompression.
  • Patch or upgrade Brotli implementations in your environment
  • If Brotli support is present (e.g., Brotli, brotlicffi, brotlipy), upgrade those packages to the versions recommended by the vendor — for example, Brotli 1.2.0 or brotlicffi 1.2.0.0 (or later) — so that decoders respect the updated safe APIs.
  • Prefer installing Brotli via the optional urllib3 extra (urllib3[brotli]) which enforces compatible versions when upgrading urllib3.
  • Audit and update downstream dependencies
  • Identify which packages in your stack depend on urllib3. Update applications and libraries to versions that have upgraded urllib3 or apply vendor patches.
  • For large monorepos, container images, CI runners, and serverless functions, rebuild images and redeploy with the updated package set.
  • Hardening and defensive measures
  • Add resource limits for processes performing network I/O (memory cgroup limits, ulimit, container memory limits) to reduce blast radius in case of an unexpected decompression attack.
  • Implement timeouts and circuit breakers on network calls that perform streaming or accept large bodies.
  • Where possible, validate or restrict Content-Encoding headers from external endpoints or only accept trusted sources for compressed streaming responses.

Detection and hunting guidance​

  • Inventory your environments for vulnerable urllib3 versions:
  • pip: pip show urllib3
  • pip: pip list --format=columns | grep urllib3
  • For virtual environments and docker images, scan bundled packages and wheels.
  • Use dependency scanning tools (static and SCA) to find transitive uses of urllib3. Common tools include safety, pip-audit, Snyk, OS vendor scanners, and container scanning products.
  • Search your codebase for streaming usage patterns that request partial reads:
  • Look for calls to .stream(, .read( with amt set, .read1(, .read_chunked(, or .readinto( where decode_content is not explicitly set to False.
  • Search for preload_content=False usage combined with streaming decompression.
  • Monitor runtime resource spikes correlated with network calls. Rules of thumb:
  • Unexpected memory growth after initiating an HTTP stream.
  • High CPU usage tied to a process that recently performed a streaming read.
  • Repeated crashes or OOM kills of worker processes that handle external HTTP responses.

Special considerations for popular downstreams​

  • Many higher-level HTTP libraries and SDKs rely on urllib3 as a dependency; check whether they vendor a copy of the library or declare a transitive dependency in their packaging. If a downstream bundles a vulnerable version, the application must update that bundled copy or update the consuming package version that has the fix.
  • When using the Requests library (or other wrappers built on urllib3), confirm the version of urllib3 that is actually used at runtime (Requests uses urllib3 but exact behavior depends on packaging and distribution). Inspect requests.[B]version[/B] and requests.adapters internals if needed, or check the virtual environment’s installed packages to determine which urllib3 is in effect.
  • Container images and serverless functions are common places where outdated libraries persist. Rebuild images using updated base images and updated pip constraints to avoid lingering vulnerable code.

For library authors and maintainers​

  • If your project wraps or exposes decompressors or custom ContentDecoder implementations, review the changed ContentDecoder API surface and ensure your custom decoders respect max_length semantics and do not unboundedly expand compressed input.
  • Add tests that simulate highly compressed inputs to confirm streaming reads are bounded and safe.
  • Consider offering configuration knobs to limit decompressed output per request or per read, and document safe defaults.
  • Encourage consumers to pin to safe urllib3 versions or to choose a dependency resolution strategy that prioritizes security updates for transitive dependencies.

Risk assessment and timeline considerations​

  • The vulnerability is a classical resource-exhaustion problem and is easiest to exploit where clients routinely stream content from untrusted or attacker-controlled servers.
  • The fix is effectively available now in the library’s patched release; the principal risk is delayed adoption. Real-world impact depends on how quickly environments upgrade and how exposed the applications are to attacker-controlled HTTP responses.
  • Even if a single app updates, downstream dependencies and packaged images may remain vulnerable. Treat this as a supply-chain remediation exercise: inventory, patch, rebuild, redeploy.

Practical checklist (quick operations playbook)​

  • Query environments to find urllib3 versions.
  • Prioritize services where streaming compressed content is used and that accept responses from untrusted endpoints.
  • Upgrade to urllib3 >= 2.6.0 in all environments; rebuild containers and serverless packages.
  • Upgrade Brotli-related packages to recommended patched versions.
  • If upgrade is impossible immediately, change streaming calls to decode_content=False and implement controlled decompression with explicit bounds.
  • Add monitoring rules for memory/CPU spikes after streaming requests.
  • Re-run SCA tools and dependency scanners to ensure no residual vulnerable copies remain.
  • Communicate the risk and remediation window to product owners and incident response teams.

Why this matters to Windows and enterprise deployments​

Windows-based Python deployments — developer machines, automated build agents, background services, and custom tooling — often carry Python packages installed via pip, packaged pictures, or vendor-supplied installers. In enterprise settings, the diversity of environments (virtualenvs, system Python, packaged applications) increases the chance that vulnerable copies persist in overlooked images or legacy deployments.
  • Containerized workloads running on Windows nodes must be rebuilt.
  • Packaging systems that freeze dependencies (wheels, zipapps, PyInstaller bundles) should be re-created from updated dependencies and re-released.
  • CI runners and agency tools that stream compressed artifacts (e.g., retrieving compressed logs, artifacts, or manifests) are particularly high-value targets for opportunistic DoS attacks.
Applying the fix universally reduces the potential for an attacker to trigger costly outages across multiple services.

Conclusion​

CVE-2025-66471 is a high-severity, high-impact vulnerability in urllib3’s streaming decompression logic that enables remote resource exhaustion through crafted compressed HTTP responses. The fix is available in urllib3 v2.6.0 and later; the fastest and most reliable remediation is to upgrade urgently, update any Brotli decoder packages as recommended, and audit downstream software for vendorized or transitive vulnerable copies.
Where immediate upgrading is infeasible, temporarily disable automatic decoding during streaming and implement bounded, explicit decompression logic. Complement code changes with operational controls — resource limits, monitoring, and dependency scanning — to reduce the attack surface and detect attempts to exploit decompression amplification.
This issue underscores a persistent lesson for modern software supply chains: streaming and decompression are powerful but perilous operations. Enforce conservative defaults, keep third-party libraries current, and instrument applications so that a single response cannot unexpectedly exhaust memory or compute resources.

Source: MSRC Security Update Guide - Microsoft Security Response Center
 

Back
Top