Aug 17, 2026·6 min read·2 visits
sqlparse prior to 0.6.0 is vulnerable to O(N^2) CPU exhaustion (ReDoS) when processing SQL strings with unmatched PostgreSQL dollar-quoted tags or unclosed multiline comments.
A high-severity Regular Expression Denial of Service (ReDoS) vulnerability in the sqlparse Python library prior to version 0.6.0 allows unauthenticated remote attackers to trigger CPU exhaustion and application denial of service via crafted SQL inputs containing unmatched dollar-quoted literals or unclosed multiline comments.
The sqlparse library is a widely deployed, non-validating SQL parser module for Python, commonly used to tokenize, format, and split SQL queries. Because it handles raw SQL strings from potentially untrusted sources, it is an entry point for processing external inputs in database administration tools, ORMs, and query sanitization engines.
A critical vulnerability, classified as CVE-2026-59893, is present in the core lexical analyzer of sqlparse prior to version 0.6.0. The vulnerability belongs to the Regular Expression Denial of Service (ReDoS) category, tracked under CWE-1333. The issue arises from inefficient regular expression evaluation when handling block-style SQL constructs, such as PostgreSQL-style dollar-quoted literals and standard SQL multiline comments.
An unauthenticated remote attacker can exploit this vulnerability by submitting a crafted SQL string containing numerous unmatched opening delimiters. Processing this payload causes the regex engine to perform quadratic backtracking, leading to high CPU utilization. This resource exhaustion results in a complete Denial of Service of the application performing the SQL parsing.
The underlying root cause resides in the regular expression patterns defined in sqlparse/keywords.py that identify block-style delimiters. The expression used for dollar-quoted literals is defined with a lazy dot-all quantifier: ((?<![\w"\$])\$(?:[_A-ZÀ-Ü]\w*)?\$)[\s\S]*?\1. This pattern matches any characters up to the matching closing delimiter backreference.
Similarly, multiline comments are identified using the patterns /\*\+[\s\S]*?\*/ and /\*[\s\S]*?\*/. When these expressions are evaluated against an input string containing unmatched opening delimiters, the lazy match [\s\S]*? continues consuming characters until it reaches the end of the text. Because there is no matching closing delimiter, the match fails, forcing the regex engine to backtrack.
The issue is amplified by the main lexer loop in sqlparse/lexer.py. The loop evaluates each regular expression sequentially at every character position in the input string. Consequently, for $N$ unmatched opening delimiters, the engine scans the remaining string of length $N, N-1, N-2, \dots, 1$, resulting in a quadratic processing complexity of $O(N^2)$.
Prior to version 0.6.0, the lexer evaluated the vulnerable regular expressions directly during sequential scanning. Because there was no pre-filtering, every unique opener triggered a complete scan of the remaining string. The following snippet shows the vulnerable configuration within sqlparse/keywords.py:
# sqlparse/keywords.py (Prior to 0.6.0)
SQL_REGEX = [
(r'/\*\+[\s\S]*?\*/', tokens.Comment.Multiline.Hint),
(r'/\*[\s\S]*?\*/', tokens.Comment.Multiline),
# ...
(r'((?<![\w"\$])\$(?:[_A-ZÀ-Ü]\w*)?\$)[\s\S]*?\1', tokens.Literal),
]The security patch implemented in commit d1d80602741f77ec78e5a04ce4719244cf32352e removes these backtracking patterns from the SQL_REGEX list. Instead, a new linear-time pre-scanning function, find_delimited_spans, is used to identify blocks. This function processes delimiters using non-backtracking patterns and pairs them left-to-right using an iterative stack model.
# sqlparse/keywords.py (Patched in 0.6.0)
_DOLLAR_QUOTE_DELIM = re.compile(r'\$(?:[_A-ZÀ-Ü]\w*)?\$', re.IGNORECASE | re.UNICODE)
_COMMENT_OPEN = re.compile(r'/\*(?!\+)')
_COMMENT_CLOSE = re.compile(r'\*/')
def find_delimited_spans(text):
# Pre-scans and resolves delimiters in a single pass
occurrences.sort(key=lambda occ: occ.start)
spans = resolve_paired_delimiters(occurrences)
return {start: (end, ttype) for start, end, ttype in spans}The lexer loop in sqlparse/lexer.py was also modified to check the pre-scanned delimited_spans dictionary before executing any active regex checks. If the current position matches a pre-resolved span, the parser yields the complete token and skips the entire block using the consume utility, avoiding redundant evaluations.
Exploiting CVE-2026-59893 requires sending a SQL payload with a large number of unclosed delimiters. For dollar-quoted literals, the payload must consist of unique tags to prevent intermediate matching. For example, $a0$x $a1$x $a2$x ... $aN$x represents a structure where each identifier is treated as a unique, unmatched delimiter.
Similarly, a comment payload can be crafted by repeating unclosed comments separated by non-comment characters, such as /*x /*x /*x ... /*x. Without the space or letter separator, contiguous comment sequences can trigger quick-fail rules; spacing forces full validation at each index.
Because the processing occurs on the main thread during tokenization, a single HTTP request containing a relatively small payload can consume excessive CPU time. In single-threaded Python application frameworks, this blocks the entire service worker, preventing other network requests from being processed.
> [!WARNING] > Attackers can automate concurrent submissions of these payloads to completely exhaust multiple server workers, resulting in a persistent denial of service.
The impact of CVE-2026-59893 is focused entirely on application availability. The CVSS 3.1 base score is 7.5, reflecting a High severity rating. The vector is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H.
Because sqlparse is widely integrated across Python frameworks, the vulnerability has broad system-level exposure. It impacts dependent tools like Django Debug Toolbar, query formatters, and database synchronization scripts. In cloud environments with auto-scaling enabled, exploitation can lead to increased infrastructure costs as new instances are continuously provisioned to handle the artificially inflated CPU demand.
There is no potential for confidentiality loss or integrity compromise, as the bug does not allow arbitrary code execution or memory corruption. However, the ease of crafting the payload and the prevalence of the library make this a high-priority vulnerability for security teams to address.
The primary remediation for CVE-2026-59893 is to upgrade sqlparse to version 0.6.0 or later. This release replaces the backtracking regex patterns with a linear-time pre-scanning and pairing algorithm. To execute the upgrade, update requirements files or run the upgrade command directly:
pip install --upgrade sqlparse>=0.6.0If upgrading is not immediately possible, you can implement input validation to restrict the maximum length of user-supplied SQL strings. Setting a maximum threshold of 10,000 characters prevents payloads from containing enough delimiters to cause severe CPU degradation.
Web application firewalls can also be configured with rules to identify and block requests containing multiple unmatched comment markers or dollar-sign symbols. Additionally, wrapping calls to sqlparse APIs in secondary threads or processes with timeout handlers ensures that runaway execution can be safely terminated.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
sqlparse Andi Albrecht | < 0.6.0 | 0.6.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1333 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 7.5 (High) |
| Exploit Status | Proof-of-Concept Available |
| Affected Component | Lexer Engine (sqlparse/keywords.py) |
| Vulnerability Class | Regular Expression Denial of Service (ReDoS) |
The product uses a regular expression with an inefficient complexity that can be exploited to cause a denial of service via resource exhaustion.
MLflow prior to version 3.15.0 fails to perform proper authorization checks when registering model versions, allowing authenticated users with access to a registered model to link and access artifacts from runs and models belonging to other users without authorization.
A high-severity logic inversion flaw in the uniget CLI completely bypasses Sigstore cryptographic signature verification on metadata files by default. If an attacker can poison the package metadata cache or repository, they can execute arbitrary OS commands under the privileges of the active user.
A technical analysis of CVE-2026-59903 in Netty's HTTP CORS handler, where the CorsHandler overwrites existing application Vary headers with Origin, leading to unauthorized caching of sensitive information.
An uncontrolled resource consumption vulnerability in Netty's SctpMessageCompletionHandler allows unauthenticated remote attackers to cause a Denial of Service. By transmitting a series of large, fragmented Stream Control Transmission Protocol (SCTP) messages, an attacker can exhaust the Java Virtual Machine heap or direct memory. This occurs because the handler fails to enforce limits on the cumulative byte size of buffered, incomplete SCTP fragments.
A command injection bypass vulnerability exists in the Glances system monitoring tool prior to v4.5.6. This flaw permits an attacker with local process or container metadata control to bypass action-template sanitizers by reconstructing shell execution operators across adjacent unescaped variables. When a system alert triggers a configured action template, the reconstructed operators are evaluated by the underlying shell, leading to arbitrary code execution in the context of the Glances process.
Grav CMS prior to version 1.7.53 and 2.0.0-rc.8 is vulnerable to an unauthenticated remote denial of service (DoS) vulnerability. By supplying crafted query parameters with extremely large dimensions to image assets, remote unauthenticated attackers can force the server to allocate massive amounts of system memory, leading to kernel Out-Of-Memory (OOM) termination of web worker processes.