CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-21441

CVE-2026-21441: The Infinite Breath of urllib3

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 23, 2026·6 min read·404 visits

Executive Summary (TL;DR)

urllib3 < 2.6.3 automatically decompresses response bodies even when merely trying to 'drain' a connection for a redirect. Attacker sends a 302 Found with a 'zip bomb' body -> Client RAM evaporates -> Service crashes.

A high-severity logic flaw in urllib3, the Python ecosystem's most popular HTTP client, allows for Denial of Service via decompression bombs. When handling HTTP redirects in streaming mode, the library inadvertently decompressed the response body of the redirect (3xx) before discarding it. This allows an attacker to send a small, highly compressed payload (like a zip bomb) inside a redirect response, forcing the client to expand it into gigabytes of data in memory, crashing the application instantly.

The Hook: Trust Issues in the Supply Chain

If you write Python, you use urllib3. You might not know it—you probably use requests—but urllib3 is the engine room. It handles the dirty work: connection pooling, SSL verification, and socket management. It is the plumbing of the Python internet.

One of the most useful features of this plumbing is preload_content=False (or stream=True in Requests). This tells the library: "Hey, I'm expecting a big file. Don't download it all at once. Let me sip it byte by byte." It's a safety mechanism, designed specifically to prevent your memory from exploding when fetching large datasets.

But CVE-2026-21441 proves that even safety mechanisms can be weaponized. It turns out that while urllib3 was busy protecting you from the final destination's payload, it was completely exposing your jugular to the journey there. Specifically, the redirect. It's a classic case of the "confused deputy"—the library tries to be helpful by cleaning up a socket, and in doing so, it commits suicide.

The Flaw: The Janitor Who Knew Too Much

To understand this bug, you have to understand HTTP Keep-Alive. When a client makes a request and receives a response, it wants to reuse that TCP connection for the next request to save overhead. But you can't reuse a socket if there is still leftover data sitting in the pipe from the previous response. You have to "drain" it.

In urllib3, when a server responds with a redirect (like a 302 Found), the library decides to follow it. But before it can send the request to the new location, it must scrub the socket clean of the old response (the 302 body). Enter the drain_conn() method.

Here is the logic failure: drain_conn() was implemented by simply calling self.read(). The developers assumed read() would just pull bytes off the wire and toss them into the void.

However, urllib3 is helpful. Too helpful. If the server sends a Content-Encoding: gzip header, self.read() automatically triggers the decompression logic. It doesn't care that you are just trying to flush the toilet; it inspects the contents anyway. The library sees a compressed stream, thinks "I bet the user wants this inflated," and expands it into RAM. All of it. All at once.

The Code: A One-Line Catastrophe

The vulnerability lived in src/urllib3/response.py. It's a masterclass in how a single line of innocuous code can bring down a production cluster.

Here is the vulnerable implementation of the drain function. Notice the lack of parameters passed to read():

# VULNERABLE CODE (urllib3 < 2.6.3)
def drain_conn(self) -> None:
    try:
        # The fatal flaw: read() defaults to decode_content=True
        # if a compression header is present.
        self.read()
    except (HTTPError, OSError, BaseSSLError, HTTPException):
        pass

When read() is called without arguments, it checks the Content-Encoding header. If it sees gzip, deflate, br, or zstd, it initializes the decompressor and runs the stream through it.

Here is the fix implemented in version 2.6.3. It explicitly tells the read method: "Do not decode this unless we have already started decoding it."

# PATCHED CODE (urllib3 >= 2.6.3)
def drain_conn(self) -> None:
    try:
        self.read(
            # The Fix: explicitly forbid decoding during the drain
            # unless the user had already started reading it.
            decode_content=self._has_decoded_content,
        )
    except (HTTPError, OSError, BaseSSLError, HTTPException):
        pass

This simple boolean flag decode_content makes the difference between a healthy service and an OOM (Out of Memory) crash.

The Exploit: Building the Bomb

To exploit this, an attacker doesn't need complex memory corruption or ROP chains. They just need a basic understanding of compression algorithms. The goal is Asymmetric Resource Exhaustion: send a few kilobytes of data that the victim expands into gigabytes.

The Attack Chain

  1. The Setup: The attacker sets up a malicious HTTP server.
  2. The Trap: The victim (a web crawler, a webhook consumer, or an image fetcher) connects to the attacker's URL.
  3. The Payload: The attacker returns a 302 Found status code. Crucially, they add Content-Encoding: gzip and a body consisting of a "zip bomb" (e.g., a stream of infinite zeros compressed via DEFLATE).

Because the expansion happens inside the library's internal "cleanup" routine, the application developer's safeguards (like reading chunks of 1024 bytes) are ignored. The library tries to drain the entire redirect body before handing control back to the application.

The Impact: Denial of Everything

This vulnerability is particularly nasty because of where urllib3 sits in the ecosystem. It is the bedrock of Python automation.

  • AI Agents & Scrapers: Any tool designed to "fetch URL content" is vulnerable. If an LLM agent is asked to summarize a webpage, and that webpage redirects to a bomb, the agent crashes.
  • Webhooks: Services that verify outgoing webhooks often follow redirects to check for final destination validity. They are instant targets.
  • Microservices: Internal services often use HTTP to talk to each other. If an attacker can inject a URL into a parameter that gets fetched (SSRF-lite scenario), they can crash the backend worker.

This is a Denial of Service (DoS) vulnerability. While it doesn't offer Remote Code Execution (RCE) directly, the operational impact is massive. A single malicious request can take down a worker process consuming 100% CPU and MAX RAM until the OS kills it.

The Fix: Remediation and Defense

The remediation is straightforward, but the urgency is high given the ubiquity of the library.

1. Patch Immediately

Upgrade urllib3 to version 2.6.3 or higher. This version was released on January 7, 2026.

pip install --upgrade urllib3
# OR if you use requests
pip install --upgrade requests

> [!NOTE] > Ensure you check your transitive dependencies. Even if your direct code doesn't import urllib3, your other libraries likely do.

2. Configuration Hardening

If you cannot patch immediately, you can mitigate this by disabling automatic redirects in your HTTP calls. This forces your application to handle the 3xx response manually, where you can choose to discard the body without reading it.

# Mitigation: Disable automatic redirects
http = urllib3.PoolManager()
response = http.request('GET', 'http://untrusted-source.com', redirect=False)

3. Network Defense

While difficult to detect at the network layer (since the payload is valid compressed data), WAFs can be configured to block responses with unusually high compression ratios if they are performing SSL termination and inspection, though this is computationally expensive.

Official Patches

urllib3Official patch commit

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H
EPSS Probability
0.03%
Top 91% most exploited

Affected Systems

Python applications using requests (indirectly)Python applications using urllib3 directlyWeb scrapers / CrawlersMicroservices fetching external URLsLLM Agents performing web browsing

Affected Versions Detail

Product
Affected Versions
Fixed Version
urllib3
urllib3
>= 1.22, < 2.6.32.6.3
AttributeDetail
CWE IDCWE-409 (Improper Handling of Highly Compressed Data)
CVSS v4.08.9 (High)
Attack VectorNetwork (Response to Outbound Request)
Affected Componenturllib3.response.drain_conn
Privileges RequiredNone
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1499.003Endpoint Denial of Service: OS Resource Exhaustion
Impact
T1210Exploitation of Remote Services
Lateral Movement
CWE-409
Improper Handling of Highly Compressed Data (Data Amplification)

The software handles a compressed data bundle but does not strictly limit the size of the uncompressed data, allowing for resource exhaustion.

Known Exploits & Detection

GitHub Security AdvisoryTechnical description and reproduction steps provided by maintainers.

Vulnerability Timeline

Vulnerable version 2.6.2 released
2025-12-11
Vulnerability Disclosed & Patched (2.6.3)
2026-01-07
NVD Analysis Published
2026-01-23

References & Sources

  • [1]GHSA-38jv-5279-wg99
  • [2]NVD CVE-2026-21441

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•CVE-2026-9800
8.1

CVE-2026-9800: Authorization Bypass in Keycloak Policy Enforcer via Unnormalized URI Substring Matching

CVE-2026-9800 is an authorization bypass vulnerability affecting the Keycloak Policy Enforcer (org.keycloak:keycloak-policy-enforcer), which is integrated into Red Hat build of Keycloak, Red Hat build of Quarkus, Red Hat Single Sign-On 7, and Red Hat JBoss Enterprise Application Platform Expansion Pack. The flaw stems from improper comparison logic in the PolicyEnforcer.isDefaultAccessDeniedUri method, which uses loose substring matching on the full raw request URI rather than exact, normalized path comparisons against the configured access-denied landing page. Consequently, an authenticated attacker possessing any valid low-privileged token can bypass role-based, scope-based, and User-Managed Access (UMA) policy evaluations by embedding the access-denied path segment into the URL path or query parameters.

Amit Schendel
Amit Schendel
1 views•8 min read
•about 2 hours ago•CVE-2026-9799
4.6

CVE-2026-9799: Authorization Bypass via UMA Permission Ticket Wildcard in Keycloak

CVE-2026-9799 is an authorization bypass vulnerability in the User-Managed Access (UMA) subsystem of Keycloak (org.keycloak.authorization). When a resource server is configured with the non-default PERMISSIVE policy enforcement mode, an authenticated user holding a valid UMA permission ticket for a single typed resource can obtain an authorization Requesting Party Token (RPT) granting access to all resources of the same type across the resource server. By submitting an authorization request with the type selector prefix 'resource-type-any:<type>', the attacker bypasses instance-level owner approval checks for unshared peer resources that lack explicit static administrative policies.

Alon Barad
Alon Barad
3 views•9 min read
•about 3 hours ago•CVE-2026-9083
4.9

CVE-2026-9083: Arbitrary Filesystem Path Probing in Keycloak Java Keystore Key Provider

CVE-2026-9083 is a path traversal and information disclosure vulnerability (CWE-22) affecting Keycloak and the Red Hat build of Keycloak. The vulnerability resides in the Java Keystore key provider component (JavaKeystoreKeyProviderFactory), which fails to restrict the user-supplied keystore file path to a designated directory. An authenticated realm administrator holding the 'manage-realm' role can supply arbitrary absolute or relative filesystem paths when configuring a key provider. Because the application returns distinct error messages depending on whether the target path does not exist, lacks read permissions, or fails keystore parsing, an attacker can use this component as an oracle to probe the underlying host filesystem.

Alon Barad
Alon Barad
4 views•11 min read
•about 4 hours ago•CVE-2026-9086
7.3

CVE-2026-9086: Stored Cross-Site Scripting via Case-Sensitive URI Scheme Validation Bypass in Keycloak

CVE-2026-9086 is a stored Cross-Site Scripting (XSS) vulnerability in Keycloak and the Red Hat build of Keycloak. The vulnerability stems from a case-sensitive URI scheme validation check in DefaultClientValidationProvider, allowing attackers with client registration or management permissions to inject javascript: or data: URIs using mixed-case characters.

Amit Schendel
Amit Schendel
5 views•10 min read
•about 5 hours ago•CVE-2026-62290
7.3

CVE-2026-62290: ClusterIssuer DNS01 Solver Policy Bypass and Credential Exfiltration in cert-manager

CVE-2026-62290 is an incorrect authorization vulnerability (CWE-863) in cert-manager that allows low-privileged Kubernetes namespace tenants to bypass ClusterIssuer DNS01 solver policies and exfiltrate cluster-scoped DNS credentials. By directly creating standalone ACME Challenge custom resources rather than going through the standard Certificate and Order workflow, an attacker can specify arbitrary solver provider configurations while referencing a privileged ClusterIssuer. The cert-manager ACME challenge controller reconciles these directly instantiated Challenge resources without verifying their parentage or validating the user-supplied solver parameters against the referenced ClusterIssuer's selector policies.

Amit Schendel
Amit Schendel
7 views•9 min read
•about 6 hours ago•CVE-2026-118662
6.9

CVE-2026-118662: Access Control Bypass via Uncanonicalized Query Parameters in Vite Development Server

CVE-2026-118662 (also tracked as GHSA-8g5g-mxqh-grgj) is an improper access control and path canonicalization vulnerability in the Vite frontend build and development tool. In version 6.4.4, the Vite development server fails to strip transform and loader query parameters before evaluating file paths against the `server.fs.deny` configuration directive. When the development server is exposed to a network and sensitive files located within `server.fs.allow` match patterns in `server.fs.deny`, an unauthenticated remote attacker can bypass file access restrictions by appending specific query strings such as `?raw` or `?inline` to HTTP requests. This allows arbitrary retrieval of restricted files, including environment configuration files and private cryptographic keys.

Alon Barad
Alon Barad
8 views•11 min read