CVE-2026-21441
High · 8.6Decompression-bomb safeguards bypassed when following HTTP redirects (streaming API)
CVSS
8.6
EPSS
2.9%
Published
Jan 7, 2026
CISA due date
—
Cloudanix analysis
A malicious website can make affected Python-based software waste large amounts of memory and processing power simply by sending a specially compressed redirect response.
- Exploitation
- Remote Unauthenticated
- Attacker needs
- None
- Complexity
- Low
- Impact
- Denial Of Service
- Component
- Library
- Class
- Denial of service
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
This vulnerability is a client-side denial-of-service flaw in urllib3’s streaming HTTP response handling. When a streamed request receives an HTTP redirect response with a compressed body, urllib3 drains the entire response body to reuse the connection and performs decompression even though the caller has not requested the body content. Configured streaming read limits do not cap the decompressed output in this path, allowing a malicious or compromised HTTP server to return a small compressed redirect body that expands into very large data. The result can be excessive CPU consumption and large memory allocation in the client process, potentially causing application slowdowns, process crashes, worker exhaustion, or container/node resource pressure.
Why it matters to the business
Applications, automation jobs, package managers, agents, or services that use affected urllib3 streaming behavior to contact untrusted or attacker-controlled HTTP endpoints can be made unavailable or unstable. The practical impact is service degradation, failed background jobs, increased infrastructure costs from CPU and memory spikes, and potential cascading failures where many workers or clients process malicious redirects at the same time. Although this issue is not listed in CISA KEV and has no reported ransomware association, the CVSS score is high and urllib3 is widely used across Python software, so organizations should prioritize remediation in internet-facing clients, crawlers, integrations, CI/CD jobs, and systems that fetch URLs from user-controlled or third-party sources.
How an attack unfolds
An attacker positions or controls an HTTP server that a vulnerable urllib3-based client will request, either directly, through a user-supplied URL, through a compromised third-party endpoint, or through a redirect chain. The server returns an HTTP redirect response, such as a 301, 302, 303, 307, or 308, and includes a compressed response body with a high compression ratio using an encoding such as gzip, deflate, brotli, or zstd. When the vulnerable client receives the redirect while using urllib3’s streaming API, urllib3 attempts to drain the redirect response body so the connection can be reused. During that drain operation, it unnecessarily decompresses the body before application code explicitly reads it, and the normal read limits do not effectively bound the decompressed size. A decompression bomb can therefore force the client process to spend excessive CPU cycles and allocate large amounts of memory. Repeated requests or many parallel clients can turn this into a reliable denial of service against application workers, scheduled jobs, or infrastructure nodes.
How to fix it
Upgrade urllib3 and downstream packages to versions that include the upstream fix. For source-based deployments, ensure urllib3 includes commit 0248277dd7ac0239204889ca991353ad3e3a1ddc or a later release containing the fix. For Debian-tracked packages in the supplied data, apply the relevant fixed package updates: Debian 11 fixed in 5.10.127-1; Debian 12, 13, and 14 fixed in 5.18.5-1. Because urllib3 is commonly vendored or pulled transitively by other Python packages, update lockfiles, rebuild containers, refresh virtual environments, and redeploy applications rather than only updating the base OS. Where immediate upgrade is not possible, reduce exposure by avoiding streaming requests to untrusted URLs, disabling automatic redirects where feasible, rejecting redirects from untrusted hosts, enforcing strict allowlists for outbound destinations, applying network egress controls, setting conservative process/container memory limits, and blocking or limiting compressed redirect responses at proxies where practical.
How to confirm the fix worked
Confirm remediation by inventorying Python environments, containers, virtual environments, application dependencies, and vendored libraries for affected urllib3 versions or code paths. Use package manager output, software composition analysis, SBOMs, and lockfiles to verify that urllib3 has been upgraded to a fixed release or contains commit 0248277dd7ac0239204889ca991353ad3e3a1ddc or later. For Debian systems, verify the installed package versions meet or exceed the listed fixed versions for the applicable release. Functional validation can include a controlled test server that returns a redirect with a compressed body and confirming that the client does not decompress unbounded content, does not allocate excessive memory, and respects expected limits. Also verify that container images and deployed runtime artifacts were rebuilt after dependency updates, because build-time lockfiles and runtime packages can diverge.
Typical attack path
- Identify an application, agent, job, or service that uses affected urllib3 streaming functionality to fetch HTTP or HTTPS URLs.
- Cause the client to request an attacker-controlled or compromised endpoint, for example through user-supplied URLs, external integrations, webhooks, package metadata, crawlers, or redirectable third-party content.
- Return an HTTP redirect response with a compressed response body and a Content-Encoding value such as gzip, deflate, br, or zstd.
- Craft the compressed body so it is small on the wire but expands to very large decompressed output.
- Rely on vulnerable urllib3 behavior to drain and decompress the redirect body before caller read methods are invoked and without enforcing configured decompressed read limits.
- Repeat or parallelize requests to exhaust CPU, memory, application workers, containers, or hosts, resulting in denial of service.
How to detect it
Look for signs of resource exhaustion in processes that make outbound HTTP requests with Python libraries. Useful sources include application logs, outbound proxy logs, web gateway logs, EDR telemetry, container metrics, host metrics, Python exception traces, orchestrator events, and process accounting. Focus on time windows where Python services show sudden CPU saturation, memory growth, out-of-memory kills, container restarts, worker timeouts, or degraded job throughput. Correlate those events with outbound HTTP responses returning 301, 302, 303, 307, or 308 status codes that also include Content-Encoding headers such as gzip, deflate, br, or zstd and unusually small transferred byte counts relative to high client-side CPU or memory use. Review whether the destination host was newly contacted, user-supplied, recently changed, or part of a redirect chain. Because exploitation may not leave a unique payload artifact, detection should emphasize behavioral correlation: compressed redirect responses followed immediately by high resource consumption, Python worker crashes, OOM events, or repeated retries to the same external endpoint.
- Content-Encoding: gzip
- Content-Encoding: deflate
- Content-Encoding: br
- Content-Encoding: zstd
- HTTP/1.1 301
- HTTP/1.1 302
- HTTP/1.1 303
- HTTP/1.1 307
- HTTP/1.1 308
- TooManyRedirects
- MemoryError
- Killed process
- Out of memory
- OOMKilled
- Exit Code 137
- urllib3.response
- urllib3.connectionpool
- decode_content=True
What your security team should do
- Prioritize patching applications and automation that fetch external, user-controlled, or third-party URLs using Python HTTP clients, especially crawlers, webhook processors, CI/CD tasks, package downloaders, and integration services.
- Perform software composition analysis across source repositories, lockfiles, container images, virtual environments, and vendored dependencies to locate urllib3 usage, including transitive dependencies through requests, botocore, and other Python libraries.
- Upgrade urllib3 to a fixed version or codebase containing commit 0248277dd7ac0239204889ca991353ad3e3a1ddc, then rebuild and redeploy affected applications and images.
- Apply Debian fixed package updates where applicable: Debian 11 fixed in 5.10.127-1; Debian 12, 13, and 14 fixed in 5.18.5-1.
- Temporarily disable automatic redirects, restrict outbound destinations, or enforce URL allowlists for high-risk services until upgrades are complete.
- Add monitoring for unusual CPU and memory spikes correlated with outbound HTTP requests, redirect responses, or compressed response handling.
- Review outbound proxy, EDR, application, and infrastructure telemetry for evidence of repeated compressed redirects from the same external hosts.
- Ensure workload resource limits, retry limits, and circuit breakers are configured so decompression-related failures do not cascade across worker pools.
The record
urllib3's [streaming API](https://urllib3.readthedocs.io/en/2.6.2/advanced-usage.html#streaming-and-i-o) is designed for the efficient handling of large HTTP responses by reading the content in chunks, rather than loading the entire response body into memory at once. urllib3 can perform decoding or decompression based on the HTTP `Content-Encoding` header (e.g., `gzip`, `deflate`, `br`, or `zstd`). When using the streaming API, the library decompresses only the necessary bytes, enabling partial content consumption. However, for HTTP redirect responses, the library would read the entire response body to drain the connection and decompress the content unnecessarily. This decompression occurred even before any read methods were called, and configured read limits did not restrict the amount of decompressed data. As a result, there was no safeguard against decompression bombs. A malicious server could exploit this to trigger excessive resource consumption on the client (high CPU usage and large memory allocations for decompressed data; CWE-409).
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| PyPI | urllib3 | 1.22 | 2.6.3 |
| AlmaLinux:10 | python3-urllib3 | 0 | 1.26.19-2.el10_1.1 |
| AlmaLinux:8 | python3-urllib3 | 0 | 1.24.2-9.el8_10 |
| AlmaLinux:8 | python3.11-urllib3 | 0 | 1.26.12-6.el8_10 |
| AlmaLinux:8 | python3.12-urllib3 | 0 | 1.26.19-2.el8_10 |
| AlmaLinux:9 | python3-urllib3 | 0 | 1.26.5-6.el9_7.1 |
| AlmaLinux:9 | python3.11-urllib3 | 0 | 1.26.12-5.el9_7.1 |
| AlmaLinux:9 | python3.12-urllib3 | 0 | 1.26.19-1.el9_7.1 |
| Chainguard | airflow-2 | 0 | 2.11.0-r20 |
| Chainguard | airflow-3 | 0 | 3.1.5-r3 |
| Chainguard | airflow-core-2 | 0 | 2.11.0-r12 |
| Chainguard | airflow-core-3 | 0 | 3.1.5-r1 |
| Chainguard | apache-beam-python-3.11-sdk | 0 | 2.70.0-r2 |
| Chainguard | authentik | 0 | 2025.10.3-r4 |
| Chainguard | authentik-fips | 0 | 2025.10.3-r1 |
| Chainguard | az | 0 | 2.81.0-r2 |
| Chainguard | az | 0 | 2.82.0-r0 |
| Chainguard | barman-cloudnative-pg | 0 | 3.17.0-r0 |
| Chainguard | checkov | 0 | 3.2.499-r0 |
| Chainguard | confluent-docker-utils | 0 | 0.0.163-r1 |
| Chainguard | dask-gateway | 0 | 2025.4.0-r7 |
| Chainguard | dask-gateway-server | 0 | 2025.4.0-r7 |
| Chainguard | dask-kubernetes | 0 | 2025.7.0-r5 |
| Chainguard | ggshield | 0 | 1.48.0-r0 |
| Chainguard | jupyter-base-notebook | 0 | 7.5.1-r1 |
| Chainguard | jupyter-base-notebook | 0 | 7.5.2-r0 |
| Chainguard | jwt-tool | 0 | 2.3.0-r3 |
| Chainguard | k8s-sidecar | 0 | 2.2.3-r1 |
| Chainguard | kserve-storage-controller | 0 | 0.16.0-r8 |
| Chainguard | kubeflow-jupyter-web-app | 0 | 1.10.0-r9 |
| Chainguard | kubeflow-pipelines-apiserver | 0 | 2.15.0-r6 |
| Chainguard | kubeflow-volumes-web-app | 0 | 1.10.0-r7 |
| Chainguard | label-studio | 0 | 1.22.0-r1 |
| Chainguard | mlflow | 0 | 3.8.1-r1 |
| Chainguard | mlflow-iamguarded-compat | 0 | 3.8.1-r1 |
| Chainguard | opentelemetry-python-instrumentation | 0 | 0.142.0-r0 |
| Chainguard | opentelemetry-python-instrumentation | 0 | 0.60.1-r1 |
| Chainguard | pgadmin4 | 0 | 9.12-r1 |
| Chainguard | pgadmin4-fips | 0 | 9.12-r1 |
| Chainguard | py3.10-ambassador | 0 | 3.10.0-r16 |
| Chainguard | py3.11-prefect | 0 | 3.6.10-r0 |
| Chainguard | py3.11-text-generation-inference | 0 | 3.3.7-r3 |
| Chainguard | py3.12-prefect | 0 | 3.6.10-r0 |
| Chainguard | py3.13-prefect | 0 | 3.6.10-r0 |
| Chainguard | py3.14-prefect | 0 | 3.6.10-r0 |
| Chainguard | superset-5.0 | 0 | 5.0.0-r11 |
| Mageia:9 | python-urllib3 | 0 | 1.26.20-1.2.mga9 |
| SUSE:Linux Enterprise Module for Public Cloud 15 SP4 | python-urllib3 | 0 | 2.0.7-150400.7.24.1 |
| SUSE:Linux Enterprise Module for Python 3 15 SP7 | python-urllib3 | 0 | 2.0.7-150400.7.24.1 |
| SUSE:Linux Enterprise Module for Python 3 15 SP7 | python-urllib3_1 | 0 | 1.26.18-150600.3.6.1 |
| Wolfi | airflow-3 | 0 | 3.1.5-r3 |
| Wolfi | az | 0 | 2.81.0-r2 |
| Wolfi | az | 0 | 2.82.0-r0 |
| Wolfi | checkov | 0 | 3.2.499-r0 |
| Wolfi | confluent-docker-utils | 0 | 0.0.163-r1 |
| Wolfi | dask-gateway | 0 | 2025.4.0-r7 |
| Wolfi | dask-gateway-server | 0 | 2025.4.0-r7 |
| Wolfi | dask-kubernetes | 0 | 2025.7.0-r5 |
| Wolfi | ggshield | 0 | 1.48.0-r0 |
| Wolfi | jupyter-base-notebook | 0 | 7.5.1-r1 |
| Wolfi | jupyter-base-notebook | 0 | 7.5.2-r0 |
| Wolfi | jwt-tool | 0 | 2.3.0-r3 |
| Wolfi | k8s-sidecar | 0 | 2.2.3-r1 |
| Wolfi | kserve-storage-controller | 0 | 0.16.0-r8 |
| Wolfi | kubeflow-jupyter-web-app | 0 | 1.10.0-r9 |
| Wolfi | kubeflow-pipelines-apiserver | 0 | 2.15.0-r6 |
| Wolfi | kubeflow-volumes-web-app | 0 | 1.10.0-r7 |
| Wolfi | mlflow | 0 | 3.8.1-r1 |
| Wolfi | mlflow-iamguarded-compat | 0 | 3.8.1-r1 |
| Wolfi | py3.10-ambassador | 0 | 3.10.0-r16 |
| Wolfi | superset-5.0 | 0 | 5.0.0-r11 |
| openSUSE:Leap 15.6 | python-urllib3 | 0 | 2.0.7-150400.7.24.1 |
| openSUSE:Leap 15.6 | python-urllib3_1 | 0 | 1.26.18-150600.3.6.1 |
| openSUSE:Leap 16.0 | python-urllib3 | 0 | 2.5.0-160000.3.1 |
| openSUSE:Leap 16.0 | python-urllib3_1 | 0 | 1.26.20-160000.3.1 |
| openSUSE:Tumbleweed | oci-cli | 0 | 3.76.2-1.1 |
| openSUSE:Tumbleweed | python-urllib3 | 0 | 2.6.3-1.1 |
| openSUSE:Tumbleweed | python-urllib3_1 | 0 | 1.26.20-5.1 |
| pypi | urllib3 | 1.22 | No fix |
Related vulnerabilities
- CVE-2025-66471 urllib3 Streaming API improperly handles highly compressed data Also affects urllib3
- CVE-2025-66418 urllib3 allows an unbounded number of links in the decompression chain Also affects urllib3
- CVE-2025-50182 urllib3 does not control redirects in browsers and Node.js Also affects urllib3
- CVE-2025-50181 urllib3 redirects are not disabled when retries are disabled on PoolManager instantiation Also affects urllib3
- CVE-2026-4539 A security flaw has been discovered in pygments up to 2.19.2. Also affects airflow-2
- CVE-2026-30922 pyasn1 is a generic ASN.1 library for Python. Also affects airflow-2
- CVE-2026-27448 pyOpenSSL is a Python wrapper around the OpenSSL library. Also affects airflow-2
- CVE-2026-27459 pyOpenSSL is a Python wrapper around the OpenSSL library. Also affects airflow-2