Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-49476

CVE-2026-49476: Soup Sieve CSS Parser DoS Vulnerability

CVE-2026-49476 is a denial of service vulnerability in Soup Sieve CSS selector library that allows attackers to exhaust memory through crafted selectors. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-49476 Overview

CVE-2026-49476 is a denial of service vulnerability in Soup Sieve, a CSS selector library used with Beautiful Soup 4. The CSS selector parser allocates unbounded memory when compiling large comma-separated selector lists. An attacker who can supply a crafted selector string to soupsieve.compile(), or to Beautiful Soup's .select() or .select_one() methods, can force the process to allocate hundreds of megabytes of heap memory from a relatively small input. The flaw is tracked under [CWE-400] Uncontrolled Resource Consumption and is fixed in version 2.8.4.

Critical Impact

Remote attackers can trigger heap exhaustion and denial of service in any Python service that parses attacker-controlled CSS selectors through Beautiful Soup or Soup Sieve.

Affected Products

  • Soup Sieve versions prior to 2.8.4
  • Beautiful Soup 4 deployments using vulnerable Soup Sieve versions for .select() and .select_one() calls
  • Python applications invoking soupsieve.compile() on untrusted selector input

Discovery Timeline

  • 2026-07-14 - CVE-2026-49476 published to NVD
  • 2026-07-15 - Last updated in NVD database

Technical Details for CVE-2026-49476

Vulnerability Analysis

Soup Sieve compiles CSS selectors into internal SelectorList objects before matching them against parsed HTML. When a selector contains a large comma-separated list, the parser expands each branch without enforcing an upper bound on the number of compiled selectors. A short input string can therefore produce a SelectorList whose in-memory representation consumes hundreds of megabytes of heap.

The amplification factor between input length and allocated memory makes this vulnerability practical to exploit remotely. Web scrapers, HTML sanitizers, template engines, and any service that accepts user-controlled selectors are exposed. Repeated requests can exhaust available memory and crash the worker process, resulting in denial of service.

Root Cause

The root cause is the absence of a bounds check on the number of selectors produced during compilation of comma-separated selector lists. The SelectorList class in soupsieve/css_types.py did not track or cap the cumulative selector count across nested compilation calls, so recursive expansion of complex selectors grew without limit.

Attack Vector

Exploitation requires only the ability to pass a selector string to a vulnerable API. The attack is network-reachable, requires no privileges, and requires no user interaction. Any HTTP endpoint that forwards user input into soupsieve.compile(), BeautifulSoup.select(), or BeautifulSoup.select_one() can be abused.

python
# Patch excerpt from soupsieve/css_types.py
 class SelectorList(Immutable):
     """Selector list."""
 
-    __slots__ = ("selectors", "is_not", "is_html", "_hash")
+    __slots__ = ("selectors", "is_not", "is_html", "count", "_hash")
 
     selectors: tuple[Selector | SelectorNull, ...]
     is_not: bool
     is_html: bool
+    count: int
 
     def __init__(
         self,
         selectors: Iterable[Selector | SelectorNull] | None = None,
         is_not: bool = False,
-        is_html: bool = False
+        is_html: bool = False,
+        count: int = 0,
     ) -> None:
         """Initialize."""
 
         super().__init__(
             selectors=tuple(selectors) if selectors is not None else (),
             is_not=is_not,
-            is_html=is_html
+            is_html=is_html,
+            count=count
         )

Source: GitHub Commit 28108ab. The patch introduces a count field on SelectorList to track selector cardinality during compilation and enforce an upper bound.

Detection Methods for CVE-2026-49476

Indicators of Compromise

  • Sudden spikes in resident set size (RSS) of Python worker processes handling HTML parsing tasks
  • MemoryError exceptions or out-of-memory (OOM) kills in application logs referencing soupsieve or bs4.BeautifulSoup.select
  • Inbound HTTP requests containing selector parameters with unusually long comma-separated token sequences
  • Sustained high CPU usage during selector compilation followed by process termination

Detection Strategies

  • Inventory Python dependencies with pip list | grep soupsieve and flag any version below 2.8.4
  • Instrument application code paths that call soupsieve.compile(), .select(), or .select_one() to log selector length and comma counts
  • Add web application firewall (WAF) rules that reject selector-shaped parameters exceeding a defined length threshold

Monitoring Recommendations

  • Track heap allocation and OOM events on hosts running Beautiful Soup workloads using process-level telemetry
  • Alert on repeated 5xx responses correlated with worker restarts from the same source IP
  • Monitor container memory limits and restart counts for services that expose HTML or selector processing endpoints

How to Mitigate CVE-2026-49476

Immediate Actions Required

  • Upgrade Soup Sieve to version 2.8.4 or later across all Python environments
  • Audit all application code that accepts selector strings from external sources and validate input length before compilation
  • Apply request size and rate limits at the reverse proxy or WAF for endpoints that consume selectors
  • Restart long-running Python processes after upgrading to ensure the patched library is loaded

Patch Information

The fix is available in Soup Sieve 2.8.4, released via GitHub Release 2.8.4. Technical details are documented in GitHub Security Advisory GHSA-2wc2-fm75-p42x. Upgrade with pip install --upgrade soupsieve>=2.8.4 and rebuild any container images that pin an older version.

Workarounds

  • Reject selector strings longer than a conservative byte limit (for example, 1024 bytes) before passing them to Soup Sieve
  • Cap the number of commas allowed in a selector expression to bound the compiled selector count
  • Isolate HTML parsing workloads in memory-limited containers or subprocesses so an OOM does not affect the parent service
bash
# Upgrade Soup Sieve to the patched version
pip install --upgrade 'soupsieve>=2.8.4'

# Verify the installed version
python -c "import soupsieve; print(soupsieve.__version__)"

# Freeze the pinned version in requirements.txt
echo 'soupsieve>=2.8.4' >> requirements.txt

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.