GitHub Advisoryadvisory · PyPI
GHSA-f2ff-p2ww-7p4p sqlparse: Quadratic O(n²) DoS in group_comments
HIGH
Official page ↗
- Aliases
- CVE-2026-71491
- Ecosystem
- PyPI
- Packages
- sqlparse
- Severity
- High
- CVSS vector
- CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
- Weaknesses
- CWE-400, CWE-407
- Reviewed
- 2026-08-17
Affected packages
• PyPI sqlparse: < 0.6.0 → fixed in 0.6.0
Description
Summary
A comment-only statement (`-- c\n`*n) may cause a Denial of Service (DoS).
Details
Location: sqlparse/engine/grouping.py:331-341 (`group_comments`), invoked first in `group()` at `grouping.py:439`. Reachable via `sqlparse.parse()` and `sqlparse.format(sql, strip_comments=True)`.
A statement made of many single-line comments (`'-- c\n'` repeated) lexes in O(n) but `group_comments` is O(n²):
```python
def group_comments(tlist):
tidx, token = tlist.token_next_by(t=T.Comment)
while token:
eidx, end = tlist.token_not_matching(
lambda tk: imt(tk, t=T.Comment) or tk.is_newline, idx=tidx)
...
tidx, token = tlist.token_next_by(t=T.Comment, idx=tidx)
```
The `while` loop runs n times and each `token_next_by` / `token_not_matching` rescans the O(n) remaining tokens. When all tokens are comments/newlines nothing ever groups, yet the full scan is repeated per token.
Two following factors increase the severity:
1. `group_comments` runs first in `group()` (`grouping.py:439`), before the `_group_matching` token-count guard (`grouping.py:34-39`). So the entire quadratic cost is paid even on oversized input. `MAX_GROUPING_TOKENS` does not provide protection on this vector.
2. It sits on the primary sanitizer path: `format(sql, strip_comments=True)`, used by query loggers, SQL firewalls, ORMs, and migration tools.
PoC
Tested using Python 3.14:
```python
import time, sqlparse
for n in (1000, 2000, 4000):
s = "-- c\n" * n
t = time.perf_counter()
sqlparse.format(s, strip_comments=True)
print(f"n={n:5d} format(strip_comments)={1000*(time.perf_counter()-t):7.1f} ms")
```
Output:
```
n= 1000 format(strip_comments)= 106.0 ms
n= 2000 format(strip_comments)= 403.3 ms
n= 4000 format(strip_comments)= 1602.8 ms
```
Time increase of ~4× per 2× input (quadratic). `parse()` shows the identical curve. Instrumented scan counts are exactly 1.0M / 4.0M / 16.0M tokens for n=1000/2000/4000. A ~250 KB comment-only payload forces minutes of CPU regardless of the 10000 token cap.
Impact
Denial of Service
Related
Alias · CVE (1)
- CVE-2026-71491 sqlparse is a non-validating SQL parser module for Python. vulnerability