CVE-2026-85999: Regular Expression Denial of Service (ReDoS) in Soup Sieve css_parser.py
Vulnerability ID: CVE-2026-85999
CVSS Score: 5.3
Published: 2026-09-17
A polynomial-time Regular Expression Denial of Service (ReDoS) vulnerability in Soup Sieve versions prior to 2.9 allows remote unauthenticated attackers to cause CPU exhaustion and thread-pool denial of service. The vulnerability resides in the trailing whitespace and comment preprocessing step of the CSS parser. An attacker can trigger quadratic backtracking by submitting a crafted CSS selector string containing a long run of internal spaces or comments terminated by a non-matching token. This blocks the Python Global Interpreter Lock (GIL) and halts worker threads.
TL;DR
A vulnerable unanchored regular expression in Soup Sieve's CSS parser allows unauthenticated remote attackers to trigger quadratic CPU exhaustion (ReDoS) and application denial of service by submitting a crafted CSS selector containing long runs of internal whitespace or comments. This issue is resolved in version 2.9.
⚠️ Exploit Status: POC
Technical Details
- CWE ID: CWE-1333
- Attack Vector: Network
- CVSS v3.1 Score: 5.3
- EPSS Score: Not Available
- Impact: Denial of Service (DoS)
- Exploit Status: poc
- KEV Status: Not Listed
Affected Systems
- Applications utilizing BeautifulSoup 4 with Soup Sieve versions prior to 2.9 for CSS selector queries.
- Python-based web scrapers, parsers, and browser-emulators processing dynamic CSS queries.
-
soupsieve: < 2.9 (Fixed in:
2.9)
Code Analysis
Commit: cf198fc
Fix catastrophic backtracking in trailing whitespace/comment trimming
@@ -112,7 +112,7 @@
NEWLINE = r'(?:\r\n|(?!\r\n)[\n\f\r])'
WS = fr'(?:[ \t]|{NEWLINE})'
# Comments
-COMMENTS = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)'
+COMMENTS = r'(?:/\*(?:[^*]|\*(?!/))*\*/)'
# Whitespace with comments included
WSC = fr'(?:{WS}|{COMMENTS})'
# CSS escapes
@@ -183,7 +183,7 @@
# Whitespace checks
RE_WS = re.compile(WS)
RE_WS_BEGIN = re.compile(fr'^{WSC}*')
-RE_WS_END = re.compile(fr'{WSC}*$')
+RE_WS_END = re.compile(fr'^(?:[ \t]|(?:\n\r|(?!\n\r)[\n\f\r])|{COMMENTS})*')
RE_CUSTOM = re.compile(fr'^{PAT_PSEUDO_CLASS_CUSTOM}$', re.X)
RE_PSEUDO_CLASS_SPECIAL = re.compile(PAT_PSEUDO_CLASS_SPECIAL, re.I | re.X | re.U)
@@ -1321,8 +1321,9 @@ def selector_iter(self, pattern: str) -> Iterator[tuple[str, Match[str]]]:
# Ignore whitespace and comments at start and end of pattern
m = RE_WS_BEGIN.search(pattern)
index = m.end(0) if m else 0
- m = RE_WS_END.search(pattern)
- end = (m.start(0) - 1) if m else (len(pattern) - 1)
+ m = RE_WS_END.search(pattern[::-1])
+ offset = m.end(0) if m else 0
+ end = len(pattern) - (1 + offset)
Mitigation Strategies
- Upgrade to Soup Sieve version 2.9 or higher.
- Implement length validation on user-controlled CSS selector inputs.
- Sanitize input selectors by compressing multiple spaces and stripping comments prior to processing.
Remediation Steps:
- Identify instances of the soupsieve library in project dependency files (e.g., requirements.txt, pyproject.toml).
- Update the dependency version constraint to at least soupsieve>=2.9.
- Deploy the updated dependency packages to testing environments to verify compatibility.
- Execute the application performance regression tests to confirm ReDoS mitigations are active.
- Push the verified patch to production deployments.
References
Read the full report for CVE-2026-85999 on our website for more details including interactive diagrams and full exploit analysis.
Top comments (0)