Skip to content

sqlparse pinned to a vulnerable version in ingestion images: 4 CVEs fixed only in 0.6.0 #31790

Description

@ulixius9

Summary

The ingestion images ship a sqlparse that is affected by four advisories, and no version inside the declared ranges is clean — OSV reports fixed: 0.6.0 for all four, with no patched 0.5.x release.

CVE GHSA Class Fixed in
CVE-2026-54284 GHSA-pwgv-4x5q-6m9f TokenList.__init__ materializes O(subtree) per group — CPU DoS 0.6.0
CVE-2026-59893 GHSA-prg7-hcfm-mfcr ReDoS on dollar-quoted literals / multiline comments 0.6.0
CVE-2026-71491 GHSA-f2ff-p2ww-7p4p Quadratic O(n²) DoS in group_comments 0.6.0
CVE-2026-59894 GHSA-3496-9g83-7v6x Unescaped backslash breaks out of generated python/php string literals 0.6.0

The DoS advisories matter here because ingestion parses attacker-influenced SQL — query-log lineage and usage workflows feed arbitrary warehouse query history through sqlparse, so a single pathological statement can pin an ingestion worker.

Why the resolver cannot fix this

Three separate ceilings block sqlparse>=0.6.0, and all three are stale rather than substantive:

Source Pin Notes
collate-sqllineage 2.1.4 (ingestion/setup.py) sqlparse==0.5.4 2.1.5 shipped sqlparse==0.6.0; 2.1.6 reverted only the pin to stay co-installable with dbt-core. The 2.1.5 and 2.1.6 wheels are byte-identical apart from the version string.
dbt-core, transitive via collate-data-diff sqlparse<0.6.0 Every version including 1.12.2. The ceiling has been in place since the setup.pypyproject.toml migration in Nov 2025 — nine months before 0.6.0 existed. Reported upstream: dbt-labs/dbt-core#15988
Airflow constraints-3.3.0/constraints-3.12.txt sqlparse==0.5.5 Also vulnerable to all four. Applies to ingestion/Dockerfile via the openmetadata-managed-apis --constraint layer.
pip install dbt-core==1.12.2 'sqlparse>=0.6.0'
# ERROR: The conflict is caused by:
#     dbt-core 1.12.2 depends on sqlparse<0.6.0 and >=0.5.5

Compatibility evidence

0.6.0 rewrote statement splitting onto a stack-based architecture, so this deserves scrutiny rather than a rubber stamp. Differential test of 0.5.4 vs 0.6.0 over 372 SQL statements scraped from our own unit tests, plus targeted cases for every 0.5.5/0.6.0 changelog entry:

  • is_safe_sql_query — 0 verdict changes across the 372-statement corpus plus 23 adversarial forbidden-SQL shapes chosen to exercise exactly the keywords 0.6.0 re-tokenizes (BEGIN, MATERIALIZED, END CASE, ROW_FORMAT, dollar-quotes). The guard is unaffected.
  • Lineage — 744 runs across SqlParseLineageAnalyzer and sqlfluff/ansi produced 7 differences, all improvements:
    • WITH x AS MATERIALIZED (...) no longer dies with ValueError: too many values to unpack (expected 2). Under 0.5.4 that query's lineage was lost entirely.
    • Lowercase as in CREATE TABLE t as SELECT f(x) FROM u now matches uppercase AS; 0.5.4 emitted u.f -> t.f, a column that does not exist.
    • The phantom <default>.materialized source table is gone.
    • Recovered lineage on a subquery CTAS that previously returned no sources.
  • mask_query — 383 queries, 1 difference, and it is a pre-existing bug rather than a regression: masker.py masks parser._parsed_result, a single statement, so any multi-statement query already loses all but the last statement under 0.5.4 (SELECT 1..; SELECT 2.. → only the 2nd). 0.6.0's corrected splitting merely adds BEGIN TRANSACTION; …; COMMIT; to the shapes that hit it. Masking never became weaker — nothing masked before is unmasked after. Related to the already-closed Masked Query in Lineage Registration Processes Only the First SQL Statement #19122.
  • collate-sqllineage's monkeypatch of sqlparse internals still applies intactgrouping.MAX_GROUPING_DEPTH/MAX_GROUPING_TOKENS raised 100×, KEYWORDS["STRING"] retyped to Name.Builtin, and the LATERAL VIEW EXPLODE SQL_REGEX rewrite. This was the main silent-degradation risk: if a future sqlparse renames either grouping global, the patch becomes a no-op and lineage comes back quietly truncated with nothing failing.

Proposal

Override sqlparse to 0.6.0 in the image builds now, with a fail-closed import gate that asserts both the version and that the collate-sqllineage monkeypatch still bites — the CVEs are concrete and the ceilings are not.

Once dbt-labs/dbt-core#15988 lands, drop the override and raise the floor in ingestion/setup.py instead, which fixes it for everyone who installs openmetadata-ingestion from PyPI rather than only for our images.

Note this is a narrower, newer instance of the class of problem described in #26597.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status
Done ✅

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions