CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-85999

CVE-2026-85999: Regular Expression Denial of Service (ReDoS) in Soup Sieve css_parser.py

Amit Schendel
Amit Schendel
Senior Security Researcher

Sep 18, 2026·6 min read·71 visits

Executive Summary (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.

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.

Vulnerability Overview

The vulnerability designated as CVE-2026-85999 (also tracked under GHSA-j934-xhv5-fg8f) affects Soup Sieve, a CSS selector library designed for use with Beautiful Soup 4. The vulnerability is located within the preprocessing phase of CSS selector compilation inside soupsieve/css_parser.py. This component is responsible for parsing, tokenizing, and normalizing CSS queries before they are executed against structured HTML or XML trees.

An attacker who can influence the CSS selector queries processed by an application can exploit this vulnerability. The security flaw stems from an inefficient regular expression evaluation in the selector_iter function, which performs trailing trim operations on the selector patterns.

Because the trimming expression lacks a start anchor and is invoked using search methods, the Python regular expression engine evaluates candidate starting positions iteratively. This leads to excessive CPU cycles being expended when processing specific pattern distributions, degrading the availability of the host software.

Root Cause Analysis

The root cause is classified under CWE-1333: Inefficient Regular Expression Complexity and CWE-400: Uncontrolled Resource Consumption. Before tokenizing a CSS selector, the library executes a pre-processing step to strip leading and trailing whitespace and comments (WSC). The leading trim regular expression RE_WS_BEGIN is anchored with ^, ensuring linear evaluation.

However, the trailing trim regular expression, defined as RE_WS_END = re.compile(fr'{WSC}*$'), is evaluated without a start anchor. Because the .search() method is utilized, the backtracking engine of the Python re module attempts a match starting at every character offset from left to right.

When a CSS selector contains a long internal run of whitespace or comments followed by a non-matching character, the engine repeatedly attempts the greedy matching process. For a sequence of length $n$, the engine performs approximately $O(n^2)$ match operations. The failure of the end-of-string anchor $ at the terminating character forces the engine to shift by one index and retry, resulting in quadratic CPU consumption.

Code Analysis

In vulnerable versions prior to 2.9, the css_parser.py preprocessing implementation uses the following code path:

# Vulnerable Implementation
RE_WS_BEGIN = re.compile(fr'^{WSC}*')
RE_WS_END = re.compile(fr'{WSC}*$')
 
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) # Vulnerable unanchored search
    end = (m.start(0) - 1) if m else (len(pattern) - 1)

The official fix, merged in commit cf198fcddc9230f06ed39f974eba0ce076b85cda, redesigns the verification flow. The developers redefined the comment parsing structure and introduced string reversal during preprocessing to safely anchor the regular expression.

# Patched Implementation
RE_WS_END = re.compile(fr'^(?:[ \t]|(?:\n\r|(?!\n\r)[\n\f\r])|{COMMENTS})*')
 
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
    # The pattern is reversed to match trailing items using a start anchor
    m = RE_WS_END.search(pattern[::-1])
    offset = m.end(0) if m else 0
    end = len(pattern) - (1 + offset)

By reversing the pattern string and utilizing the start anchor ^ on the reversed text, the regular expression engine is constrained to match strictly from index 0. If a mismatch is encountered at the beginning of the reversed pattern, the parser fails immediately in $O(1)$ time, mitigating the backtracking loop.

Exploitation Methodology

An attack can be executed if a target web application exposes an endpoint that compiles dynamic, user-supplied CSS selectors. This is common in web scraping utilities, content filtering tools, and administrative interfaces that run structural queries.

The exploit payload requires three elements: a valid CSS element selector, a long sequence of internal whitespace characters or CSS comments, and a single trailing character that does not match the trailing rules. An example string is: 'div' + ' ' * 20000 + 'b'. Alternatively, an exploit can be crafted using repeating CSS comments: 'div' + '/*comment*/' * 2000 + 'b'.

When the backend engine parses this query, the process halts. Because Python utilizes a Global Interpreter Lock (GIL), the CPU-bound regular expression processing prevents concurrent application threads from executing, leading to denial of service.

Impact Assessment

The impact is classified as a denial of service (DoS) vulnerability. Although CVSS v3.1 assigns a Medium severity of 5.3 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L), the practical impact on Python service deployments is high.

In synchronous or multi-threaded Python application servers (e.g., gunicorn, uWSGI), a thread locked in a regular expression backtracking loop will hold the GIL continuously. This starvation blocks other threads in the same process from handling incoming requests. If an attacker submits a small number of concurrent requests matching the exploit signature, they can exhaust the available worker pools, bringing down the application.

Because this vulnerability occurs during the initial preprocessing stage of Soup Sieve, it requires minimal system knowledge to exploit. The attack is highly repeatable and requires no authentication.

Remediation & Mitigation Guidance

Remediation requires upgrading the soupsieve package to version 2.9 or above, which replaces the unanchored search pattern with the reversed-string anchored match.

To upgrade the package using pip, execute:

pip install --upgrade soupsieve

If immediate dependency updates are not possible, developers should implement input validation limits. Restrict the character length of selectors accepted from untrusted sources to a conservative ceiling (e.g., 256 characters). Developers can also sanitize input strings by compressing consecutive whitespace and stripping comments before passing the selectors to Beautiful Soup APIs.

# Defensive sanitization wrapper
import re
 
def safe_select(soup, selector):
    # Compress internal whitespace sequences and strip comment blocks
    sanitized = re.sub(r'\s+', ' ', selector)
    sanitized = re.sub(r'/\*.*?\*/', '', sanitized)
    if len(sanitized) > 512:
        raise ValueError("Selector length exceeds safe limit")
    return soup.select(sanitized)

Official Patches

facelessuserPatch commit fixing ReDoS trailing trim issue
facelessuserSoup Sieve 2.9 Official Release Tag

Fix Analysis (1)

Technical Appendix

CVSS Score
5.3/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

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.

Affected Versions Detail

Product
Affected Versions
Fixed Version
soupsieve
facelessuser
< 2.92.9
AttributeDetail
CWE IDCWE-1333
Attack VectorNetwork
CVSS v3.1 Score5.3
EPSS ScoreNot Available
ImpactDenial of Service (DoS)
Exploit Statuspoc
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499.004Endpoint Denial of Service: Application Exhaustion
Impact
CWE-1333
Inefficient Regular Expression Complexity

The product uses a regular expression that can be made to run in quadratic time relative to the input size, allowing attackers to consume excessive CPU cycles.

Vulnerability Timeline

Vulnerability fix implemented in source repository
2026-07-19
Soup Sieve version 2.9 released on PyPI
2026-09-17
GitHub Security Advisory GHSA-j934-xhv5-fg8f published
2026-09-17
CVE-2026-85999 published and assigned
2026-09-17

References & Sources

  • [1]GitHub Security Advisory GHSA-j934-xhv5-fg8f
  • [2]CVE Record CVE-2026-85999
  • [3]NVD Entry CVE-2026-85999

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•1 day ago•CVE-2026-118777
4.8

CVE-2026-118777: Prototype Pollution in Forge HTTP Client Cookie Management

CVE-2026-118777 is a prototype pollution vulnerability (CWE-1321) in the Forge JavaScript cryptography and networking library (distributed on npm as node-forge) prior to version 1.4.1. The flaw resides in the forge.http client subsystem, where incoming HTTP cookie names and paths parsed from Set-Cookie response headers are stored directly into standard JavaScript objects without key validation or property isolation. By returning crafted Set-Cookie headers containing keys such as __proto__ or constructor, a malicious HTTP server can inject arbitrary properties into Object.prototype, attach attributes to the global Object constructor, or delete built-in prototype methods to cause an application-wide denial of service.

Amit Schendel
Amit Schendel
8 views•10 min read
•1 day ago•CVE-2026-118775
3.7

CVE-2026-118775: ASN.1 OID First Arc Truncation and Ambiguity in node-forge

CVE-2026-118775 (GHSA-4642-5mcj-2rqw) is an integer overflow and validation flaw in the ASN.1 serialization module of Forge (node-forge) prior to version 1.4.1. The asn1.oidToDer() function fails to validate the range of the first two arcs of an Object Identifier (OID) and truncates the packed initial subidentifier to a single 8-bit integer. Applications that perform policy checks on untrusted OID strings before encoding them into Distinguished Encoding Rules (DER) format can be tricked into emitting DER bytes that correspond to a completely different, restricted OID.

Amit Schendel
Amit Schendel
10 views•10 min read
•1 day ago•CVE-2026-119194
7.5

CVE-2026-119194: Algorithmic Complexity Denial of Service in pyasn1 Schemaless ASN.1 Decoder

CVE-2026-119194 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting versions 0.3.3 through 0.6.4. The flaw resides in the schemaless decoding routine ConstructedPayloadDecoderBase._decodeComponentsSchemaless used across BER, CER, and DER codecs. By sending an ASN.1 container populated with child components whose tag identifiers are separated by multiples of CPython's integer hash modulus (sys.hash_info.modulus), an unauthenticated attacker can force worst-case hash collisions in an unbounded Python set, degrading decoding performance from O(N) to O(N^2) and causing a Denial of Service (DoS).

Alon Barad
Alon Barad
8 views•9 min read
•1 day ago•CVE-2026-119195
7.5

CVE-2026-119195: Quadratic-Time Denial of Service in pyasn1 BER/CER/DER Decoders

CVE-2026-119195 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting all versions prior to 0.6.5. When decoding constructed strings or indefinite-length ANY types across BER, CER, and certain DER code paths, the payload decoders repeatedly concatenate incoming fragments onto an immutable bytes object using the += operator. Because Python bytes objects cannot be resized in-place, each fragment iteration allocates a new buffer and copies all previously accumulated bytes, resulting in quadratic O(N^2) time and memory copy complexity. An unauthenticated remote attacker can supply a highly fragmented ASN.1 stream to exhaust CPU cycles and stall application worker threads.

Amit Schendel
Amit Schendel
9 views•10 min read
•1 day ago•CVE-2026-119197
7.5

CVE-2026-119197: Quadratic Algorithmic Complexity Denial of Service in pyasn1 REAL Mantissa Decoder

An algorithmic complexity vulnerability (CWE-407) in pyasn1 versions prior to 0.6.5 allows unauthenticated attackers to cause a Denial of Service (DoS) via crafted ASN.1 payloads. The flaw resides in the binary-encoded ASN.1 REAL mantissa deserialization routine within RealPayloadDecoder.valueDecoder. By performing iterative byte-string slicing and repeated bitwise shifts on a growing arbitrary-precision integer, the decoder exhibits quadratic time and memory allocation complexity relative to the mantissa length. Supplying a BER-, CER-, or DER-encoded payload with a large REAL mantissa causes excessive CPU consumption and blocks application worker processes.

Amit Schendel
Amit Schendel
8 views•10 min read
•1 day ago•CVE-2026-119196
7.5

CVE-2026-119196: Quadratic CPU Consumption in pyasn1 Constructed BIT STRING Decoding

A vulnerability classified under CWE-407 (Inefficient Algorithmic Complexity) exists in the pyasn1 library prior to version 0.6.5. When parsing constructed ASN.1 BIT STRING payloads under BER, CER, or schema-driven DER encoding rules, the BitStringPayloadDecoder repeatedly shifts and copies the entire accumulated bit value for each incoming fragment. Processing inputs with a large number of small constructed fragments induces quadratic CPU consumption, allowing unauthenticated remote attackers to cause a denial of service via resource exhaustion during the initial decoding phase.

Alon Barad
Alon Barad
9 views•10 min read