CVE-2026-97688
Executive Summary
CVE-2026-97688 is a denial-of-service vulnerability in urllib3, the widely used HTTP client library for Python, affecting versions from 2.6.2 until 2.8.0. Under a specific configuration—content decoding enabled, a positive finite streaming read size (amt=N), and a server response using Transfer-Encoding: chunked with Content-Encoding: deflate—a malicious or misbehaving server can cause HTTPResponse.stream and HTTPResponse.read_chunked to enter an infinite loop, consuming CPU indefinitely without completing the request. Any application or service that uses an affected urllib3 version to fetch data from untrusted or attacker-influenced endpoints is potentially impacted, with the primary consequence being sustained resource exhaustion on the client side.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The vulnerability is a classic CWE-835 "Loop with Unreachable Exit Condition ('Infinite Loop')" arising in urllib3's Deflate content decoder as used by the streaming and chunked-read code paths.
At a high level, urllib3's response handling pipeline decodes content encodings (such as deflate) as bytes are pulled off the socket. Per the NVD description, when a server returns a response that:
- uses
Transfer-Encoding: chunked, and - uses
Content-Encoding: deflate, and - is consumed by a client with content decoding enabled, and
- is read via
HTTPResponse.stream/HTTPResponse.read_chunkedwith a positive finiteamt=Nstreaming chunk size, and - has a decoded body larger than that finite
amt=Nchunk size, and - has trailing bytes after the end of the Deflate stream,
the Deflate decoder retains those trailing bytes as "unconsumed input" after it reaches end-of-stream. The decoding loop then repeatedly attempts to decode the same retained trailing bytes, makes no forward progress, and never terminates.
The key property that makes this a denial-of-service rather than a transient hiccup is that no further socket read occurs inside the loop: the decoder already holds the bytes it is trying to process. Consequently, network read timeouts—which normally bound how long a client waits on I/O—do not interrupt the loop, because the loop is CPU-bound on already-buffered data rather than blocked on the socket. The result is a tight CPU-consuming loop attached to a request that never completes.
The conditions are all attacker-controllable on the server side: the attacker controls both the chunked framing and the Deflate payload, including the presence of trailing bytes after the Deflate stream terminator. The only client-side preconditions are library version (2.6.2 through 2.7.x), content decoding being on (the default for many use cases), and the use of a bounded amt=N streaming/chunked read pattern.
Only the function names and behavior explicitly described in the source data are asserted here: HTTPResponse.stream, HTTPResponse.read_chunked, the Deflate decoder, the Content-Encoding: deflate and Transfer-Encoding: chunked headers, content decoding, and the positive finite amt=N chunk size. No internal decoder method names, class hierarchies, or file paths are specified in the source material and are therefore not claimed.
The fix landed in urllib3 2.8.0. Because no vendor advisory, commit hash, or CNA description was provided in the source data, the precise code change (for example, how trailing unconsumed bytes are handled or how the decode loop is bounded) cannot be stated factually and is not asserted here. The description frames the root cause as the decoder retaining trailing bytes past end-of-stream and re-decoding them without progress; the 2.8.0 fix addresses that behavior.
Exploitation Scenarios
No public proof-of-concept, exploit code, or Nuclei template is available as of this report; the attack chain below is inferred from the vulnerability class (CWE-835 in a client-side HTTP streaming decoder) and the conditions stated in the NVD description.
Reconnaissance / target identification. The attacker identifies a target application or service that (a) runs urllib3 in the affected range 2.6.2 through 2.7.x, and (b) makes outbound HTTP requests to endpoints the attacker controls or influences (for example, user-supplied URLs, federated/webhook/mirror sources, or an attacker-hosted server that a client reaches). Because the flaw is triggered by the server's response, the effective attack surface is any urllib3-based client that fetches attacker-influenced content with streaming/chunked reads and content decoding enabled.
Triggering the flaw. The attacker's server responds to the client's request with a message that satisfies every required condition simultaneously:
Transfer-Encoding: chunked, so the response is consumed via the chunked read path (HTTPResponse.read_chunked/ streaming);Content-Encoding: deflate, so the Deflate decoder is engaged (content decoding enabled);- a decoded body that exceeds the positive finite streaming chunk size the client requests (
amt=N); - trailing bytes appended after the end of the Deflate stream.
The attacker controls this response content and framing directly. When the client streams the response with the bounded
amt=Nsize, the Deflate decoder reaches end-of-stream, retains the trailing bytes as unconsumed input, and the decode loop spins without making progress.
Execution method (vulnerability-class level). This is not a code-execution or injection flaw; it is a resource-exhaustion / logic flaw. The "payload" is the crafted compressed, chunked HTTP response described above. No memory corruption, no command execution, and no credential or data disclosure is involved. Triggering requires only that the malicious response reach an affected client through a code path that uses the streaming/chunked read with a finite chunk size and content decoding.
Post-exploitation impact. The affected client enters an infinite, CPU-bound loop on a request that never completes. Because the loop operates on already-buffered bytes, no further socket read occurs and network read timeouts do not interrupt it. Sustained or repeated triggering ties up worker threads/processes and CPU on the client, degrading or denying service to that application. Multiple concurrent malicious responses can amplify the effect. There is no evidence in the source data of confidentiality or integrity impact; the effect is availability-only.
Impact Assessment
The impact is availability-only. Per the CVSS vector aligned with the description, the relevant characteristics are:
- Attack Vector: Network (AV:N) — the trigger is a server response over the network.
- Attack Complexity: Low (AC:L) — once the required client configuration is present, creating the qualifying response is straightforward for a server-side attacker.
- Privileges Required: None (PR:N) — the attacker needs no privileges on the client.
- User Interaction: None (UI:N) — no client user action is required beyond the application performing the fetch.
- Scope: Unchanged (S:U).
- Confidentiality: None (C:N); Integrity: None (I:N); Availability: High (A:H) — the request never completes and CPU is consumed indefinitely.
Blast radius depends on how and where affected urllib3 clients fetch attacker-influenced content. The most exposed cases are:
- Higher-level Python HTTP libraries and frameworks that depend on urllib3 (for example, applications using its streaming APIs) and process responses from external sources.
- Aggregation, mirroring, proxy, scraping, webhook-consumption, or federation services that pull content from many third-party endpoints and use streaming/chunked reads with content decoding.
- Multi-tenant or shared services where one crafted response can pin a worker thread indefinitely, reducing capacity for all tenants.
Because CWE-835 starvation is per-loop and typically per-request/thread, a single trigger degrades one worker; an attacker who can induce many such responses (or target a service that makes many outbound fetches) can scale this into a broader denial of service. Reported CVSS score is N/A in the source data; the vector above reflects the described availability-only impact and is not an official NVD score.
Detection Guidance
Sigma Rule
This Sigma rule targets application/EDR-visible symptoms: sustained high CPU combined with long-lived outbound HTTP handling in Python processes. Tune thresholds to the environment.
title: Potential urllib3 Deflate Infinite Loop DoS (CVE-2026-97688)
id: 9f2c7a14-3b6e-4d21-9c8f-urllib3cve97688
status: experimental
description: Detects possible exploitation of CVE-2026-97688 where an affected urllib3 client enters a CPU-bound infinite loop processing a chunked Deflate response from an untrusted server.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-97688
author: valtersit.com
date: 2026/01/01
tags:
- attack.t1190
- attack.impact
logsource:
category: process_creation
product: linux
detection:
selection_proc:
Image|endswith:
- '/python'
- '/python3'
selection_susp:
CommandLine|contains:
- 'urllib3'
- 'requests'
timeframe: 5m
condition: selection_proc and selection_susp
level: low
falsepositives:
- Legitimate long-running Python HTTP clients
- Batch data download jobs
YARA Rule
This YARA rule scans for the exact vulnerable code path markers in urllib3 source trees to help identify in-range, unfixed deployments.
rule CVE_2026_97688_urllib3_deflate_loop
{
meta:
description = "Detects urllib3 Deflate decoder handling that may be affected by CVE-2026-97688 infinite loop"
cve = "CVE-2026-97688"
author = "valtersit.com"
date = "2026-01-01"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-97688"
strings:
$s1 = "read_chunked" ascii
$s2 = "deflate" ascii nocase
$s3 = "Transfer-Encoding" ascii nocase
$s4 = "Content-Encoding" ascii nocase
$s5 = "unconsumed" ascii nocase
condition:
filesize < 2MB and
( $s1 and $s2 ) and ( $s3 or $s4 ) or $s5
}
Suricata IDS Rule
This rule alerts on the response framing that triggers the condition: a chunked response that also advertises Deflate content encoding, which is the required combination for CVE-2026-97688.
alert http any any -> any any (msg:"CVE-2026-97688 urllib3 Deflate chunked response potential infinite loop DoS"; flow:established,to_client; http.response_header; content:"Transfer-Encoding|3a| chunked"; nocase; http.response_header; content:"Content-Encoding|3a| deflate"; nocase; threshold:type limit, track by_src, count 1, seconds 60; classtype:attempted-dos; reference:cve,2026-97688; reference:url,https://nvd.nist.gov/vuln/detail/CVE-2026-97688; sid:202697688; rev:1;)
Elastic Detection
This EQL rule correlates repeated outbound HTTP fetches from Python processes with elevated CPU on the same host, consistent with a client stuck in the Deflate decode loop.
sequence by host.id with maxspan=5m
[ process where process.name in ("python", "python3") and network.direction == "egress" ]
[ process where process.name in ("python", "python3") and
process.Ext.cpu_percent_of_single_core >= 95 ]
Splunk SPL Query
This SPL search detects the server-side trigger pattern on the wire (chunked + deflate responses) and pairs it with high CPU events on Python hosts.
index=proxy OR index=network sourcetype=http
| search (response_headers=*"Transfer-Encoding: chunked"* AND response_headers=*"Content-Encoding: deflate"*)
| stats count values(server_ip) as servers by src_ip
| where count > 5
| eval cve="CVE-2026-97688", severity="high"
| table src_ip servers count cve severity
Wazuh OSSEC Rule
This Wazuh rule escalates on Python processes exhibiting sustained high CPU that may indicate the urllib3 infinite loop.
<group name="urllib3,cve-2026-97688,web,">
<rule id="100688" level="10">
<decoded_as>json</decoded_as>
<field name="process.name">python3?$</field>
<field name="cpu.usage">\.\d+</field>
<description>CVE-2026-97688 - Possible urllib3 Deflate infinite loop DoS: sustained high CPU in Python HTTP client</description>
<mitre>
<id>T1190</id>
</mitre>
<group>availability,cve_2026_97688,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 0/4 (UNPATCHED — no patch evidence from any tracked source). The NVD description states the issue is fixed in urllib3 2.8.0, but no vendor advisory, commit reference, or fix artifact was supplied in the source data; treat 2.8.0+ as the target version but validate against the vendor's own release notes before relying on it.
Immediate mitigations (before upgrading):
- Upgrade urllib3 to 2.8.0 or later wherever possible; this is the primary remediation.
- Where upgrading is not immediately feasible, reduce exposure:
- Disable or avoid automatic content decoding for requests to untrusted or user-influenced endpoints, and avoid streaming/chunked reads that use a positive finite
amt=Nchunk size against untrusted servers when practical. - Restrict which outbound endpoints affected applications may fetch from (allowlisting) to reduce the set of servers that can deliver a crafted response.
- Where the application code is controllable, avoid streaming/chunked consumption of responses from untrusted sources; use full-buffer reads with strict response size and time bounds, or wrap the fetch in an out-of-process worker with a hard kill/CPU timeout that is enforced by the parent (not by socket read timeouts, which the description states do not interrupt the loop).
- Disable or avoid automatic content decoding for requests to untrusted or user-influenced endpoints, and avoid streaming/chunked reads that use a positive finite
- Enforce per-request CPU/wall-clock limits at the process or thread level (e.g., supervisor or container-level CPU throttling and kill policy) so a stuck loop cannot pin a worker indefinitely.
- Note: network read timeouts are explicitly ineffective here because no further socket read occurs; do not rely on them.
Patch / upgrade steps:
- Identify all Python environments and dependency trees containing urllib3 versions >= 2.6.2 and < 2.8.0 (including transitive dependencies).
- Pin and upgrade urllib3 to >= 2.8.0, then rebuild/redeploy services and re-scan with your SCA tool.
- Verify in-range versions are eliminated across containers, virtual environments, and bundled distributions.
Long-term hardening:
- Treat all outbound HTTP fetches as untrusted-input processing: apply response size caps, strict decode limits, and out-of-band timeout enforcement.
- Add dependency scanning/alerting for urllib3 and its consumers so future advisories are caught quickly.
- Isolate network-fetching workers so a single stuck request cannot exhaust shared resources, and monitor for sustained single-core CPU saturation in Python HTTP clients.
References
- NVD — CVE-2026-97688: https://nvd.nist.gov/vuln/detail/CVE-2026-97688
- CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop'): https://cwe.mitre.org/data/definitions/835.html
- MITRE ATT&CK T1190 — Exploit Public-Facing Application: https://attack.mitre.org/techniques/T1190/
- urllib3 project documentation and release notes (verify fixed version 2.8.0 against upstream release notes): https://urllib3.readthedocs.io/
- EPSS: not yet scored by FIRST.org as of this report; CISA KEV: not listed. No public PoC, exploit code, or in-the-wild campaign evidence was identified in the source data.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.