CVE-2026-49476: soupsieve Memory Exhaustion via Unbounded Selector List
Passing a crafted CSS selector string with hundreds of thousands of comma-separated entries to soupsieve causes it to allocate hundreds of megabytes of memory, crashing or killing any Python web app…
The problem
The CSS parser in soupsieve imposes no limit on the number of comma-separated selectors in a single selector string. Every entry is fully parsed into a rich Selector object graph and stored in a SelectorList, consuming roughly 976 bytes of heap per item.
A 500 KB input of 250,000 repetitions of a, causes approximately 244 MB of heap allocation, a 488x amplification. Any server-side app that passes user input to soupsieve.compile(), soup.select(), or soup.select_one() is exposed, with no authentication required.
Proof of concept
A working proof-of-concept for CVE-2026-49476 in soupsieve, with the exact payload below.
import soupsieve as sv
# 500 KB selector string -> ~244 MB heap allocation
count = 250_000
selector = ",".join("a" for _ in range(count))
# triggers unbounded allocation in css_parser.py parse_selectors()
compiled = sv.compile(selector)
print(len(compiled.selectors)) # 250000The root cause is CWE-770 (Allocation of Resources Without Limits or Throttling). In soupsieve/css_parser.py, parse_selectors() iterates every comma-delimited segment and builds a full _Selector object for each one with no cap on list length. The 2.8.4 patch adds a hard upper bound on the number of selectors that parse_selectors() will accept, raising SelectorSyntaxError when the count exceeds the limit before allocating further objects.
The amplification is severe because a single ASCII character like a expands into a complex object graph including SelectorList, Selector, tag metadata, and associated structures, each costing ~976 bytes, so a compact repeated payload produces disproportionate memory growth.
The fix
Upgrade to soupsieve 2.8.4 (pip install -U soupsieve). The fix adds a selector-count ceiling in parse_selectors() inside css_parser.py, rejecting oversized selector lists before they can allocate unbounded memory. If you cannot upgrade immediately, validate and reject user-supplied selector strings that exceed a safe length threshold at the application layer before passing them to soupsieve.
Reported by Liyi Zhou, Ziyue Wang, Strick, Maurice, Chenchen Yu (University of Sydney Security Research Team).
Related research
- high · 7.5CVE-2026-49477CVE-2026-49477: soupsieve Regular Expression Denial of Service (ReDoS)
- high · 7.5CVE-2026-59939CVE-2026-59939: httplib2 Decompression Bomb Denial of Service
- high · 7.5CVE-2026-59200CVE-2026-59200: Pillow PdfParser Decompression Bomb DoS
- high · 7.5CVE-2026-50271CVE-2026-50271: ddtrace Uncontrolled Resource Consumption via W3C Baggage Header Parsing