Skip to content

CVE-2026-40900: Verified Repro With Script Download

CVE-2026-40900: DataEase: stacked-query SQL injection via previewSql with allowMultiQueries

CVE-2026-40900 is verified against dataease · github. Affected versions: <= v2.10.20. Fixed in v2.10.21. Vulnerability class: SQLi. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00169.

REPRO-2026-00169 dataease · github SQLi Variant found May 26, 2026 CVE entry ↗ .txt
Severity
HIGH
CVSS
8.8
Reproduced in
58m 29s
Tool calls
582
Spend
$11.11
01 · Overview

What Is CVE-2026-40900?

CVE-2026-40900 is a high-severity (CVSS 8.8 per the advisory) stacked-query SQL injection vulnerability (CWE-89) in DataEase's previewSql endpoint, letting an attacker execute arbitrary stacked SQL statements against the application database. Pruva reproduced it (reproduction REPRO-2026-00169).

02 · Severity & CVSS

CVE-2026-40900 Severity & CVSS Score

CVE-2026-40900 is rated high severity, with a CVSS base score of 8.8 out of 10.

HIGH threat level
8.8 / 10 CVSS base
03 · Affected Versions

Affected dataease Versions

dataease · github versions <= v2.10.20 are affected.

How to Reproduce CVE-2026-40900

$ pruva-verify REPRO-2026-00169
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00169/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-40900

Reproduced by Pruva's autonomous agents — 582 tool calls over 58 min. Full root-cause analysis and the complete transcript are below.

Variants tested

PostgreSQL time-based stacked SQL injection through DatasetDataManage.previewSql — same root cause as CVE-2026-40900 (no single-statement validation) but via a PostgreSQL datasource instead of MySQL.

How the agent worked 2,119 events · 582 tool calls · 58 min
58 minDuration
582Tool calls
510Reasoning steps
2,119Events
3Dead-ends
Agent activity over 58 min
Support
20
Repro
1,498
Variant
597
0:0058:29

Root Cause and Exploit Chain for CVE-2026-40900

Versions: <= v2.10.20Fixed: v2.10.21

CVE-2026-40900 is a stacked-query SQL injection vulnerability in DataEase's previewSql endpoint (POST /de2api/datasetData/previewSql). The endpoint accepts arbitrary user-supplied SQL and wraps it inside a subquery (SELECT * FROM ( <USER_SQL> ) AS alias LIMIT 100) without enforcing that the input is a single SELECT statement. When the underlying MySQL JDBC connection is configured with allowMultiQueries=true, an attacker can craft a payload that escapes the wrapping subquery using a closing parenthesis and semicolon, executes a second side-effecting statement (INSERT/UPDATE/DELETE), and uses a MySQL # comment to swallow the remainder of the wrapper. This grants full read/write access to the application database.

  • Package/component affected: DataEase (io.dataease:datasource:type:Mysql and dataset:manage:DatasetDataManage)
  • Affected versions: <= v2.10.20
  • Fixed versions: v2.10.21
  • Risk level: High (CVSS 3.1: 8.8)
  • Consequences: Authenticated attacker can execute arbitrary stacked SQL against the DataEase application database, including INSERT/UPDATE/DELETE on tables such as core_msg_type or Quartz scheduler tables, enabling further privilege escalation or RCE as documented in the Ox Security writeup.

Root Cause

The vulnerability has two contributing factors:

  1. Missing allowMultiQueries in MySQL JDBC parameter blocklist: In core/core-backend/src/main/java/io/dataease/datasource/type/Mysql.java (v2.10.20), the illegalParameters list did not include allowMultiQueries. This allowed an admin (or attacker who had compromised admin privileges via the preceding CVEs in the chain) to register a MySQL datasource whose JDBC URL contained allowMultiQueries=true.

  2. No single-statement validation in previewSql: DatasetDataManage.previewSql() wraps the user-provided SQL string in a subquery without parsing or validating that it is a single SELECT statement. When allowMultiQueries=true, the MySQL JDBC driver happily executes multiple statements in one call.

The attacker payload:

SELECT 1 FROM dual) AS x; INSERT INTO repro_test (id, name) VALUES (999999999, 'pwned')#

becomes:

SELECT * FROM ( SELECT 1 FROM dual) AS x; INSERT INTO repro_test ... # ) AS alias LIMIT 100

The # comments out ) AS alias LIMIT 100, leaving two valid statements, both of which MySQL executes.

Fix commit: 15611593b3631b5a25528b9cdb2ee517ef27929a — adds "allowMultiQueries" to the illegalParameters list in Mysql.java. When the datasource configuration is validated during save/update, JdbcUrlSecurityPolicy.validate() now rejects any MySQL JDBC URL or extra parameters containing allowMultiQueries, causing the datasource to be saved with status="Error". previewSql refuses to run against datasources with Error status, blocking the exploit path.

Reproduction Steps

See repro/reproduction_steps.sh for the automated end-to-end reproduction. At a high level:

  1. Start DataEase v2.10.20 + MySQL via Docker Compose.
  2. Log in as admin / DataEase@123456 (RSA-encrypted credentials fetched via /de2api/dekey).
  3. Create a MySQL datasource with extraParams=allowMultiQueries=true.
  4. Validate the datasource (succeeds on v2.10.20).
  5. Send POST /de2api/datasetData/previewSql with a base64-encoded stacked-SQL payload:
    SELECT 1 FROM dual) AS x; INSERT INTO repro_test (id, name) VALUES (999999999, 'pwned-by-cve-2026-40900')#
    
  6. Query MySQL: a new row exists in repro_test — proving the INSERT executed.
  7. Tear down, redeploy with v2.10.21, repeat the same save request.
  8. On v2.10.21 the datasource is saved but marked status="Error" because allowMultiQueries is rejected by the updated illegalParameters blocklist. previewSql refuses to run, and no side-effect occurs.

Evidence

  • logs/v2.10.20_exploit.json — HTTP response from previewSql on the vulnerable build.
  • logs/v2.10.20_validate.json — datasource validation response showing status="Success".
  • logs/v2.10.21_create_datasource.json — save response on the fixed build showing status="Error".
  • Console output from the reproduction script shows:
    • v2.10.20: Post-exploit repro_test count: 1
    • v2.10.21: datasource unusable, count: 0

Recommendations / Next Steps

  1. Upgrade to v2.10.21 or later — the vendor patch is minimal and targeted.
  2. Additional defense-in-depth: add a server-side SQL parser (e.g., JSqlParser or Calcite SQL validation) to enforce that previewSql input contains exactly one SELECT statement before wrapping it.
  3. Audit existing MySQL datasources for any that have allowMultiQueries=true in their configuration and remove or reconfigure them.
  4. Regression test: include the stacked-SQL payload in the CI pipeline for previewSql to ensure future changes don't re-introduce the bypass.

Additional Notes

  • Idempotency: The script was run twice consecutively, both times producing the same results (vulnerable side-effect confirmed on v2.10.20, blocked on v2.10.21).
  • Limitations: The reproduction requires running the full DataEase Spring Boot container and MySQL container, so each run takes ~60–90 seconds. The script handles cleanup automatically via trap cleanup EXIT.
  • The fix is in the datasource configuration layer (Mysql.illegalParameters) rather than in the previewSql query-wrapping logic itself. While this blocks the specific allowMultiQueries vector, a more robust fix would also validate the SQL structure in previewSql to defend against other JDBC-parameter bypasses.

Variant Analysis & Alternative Triggers for CVE-2026-40900

Versions: <= v2.10.20 (confirmed on v2.10.20 commit ba0052aff05d85b5ae6e81f687b777b242222dd4).Fixed: v2.10.21 (commit e1085ffb75f42b6aca117edf36b30276bfdfe9aa) blocks the MySQL-specific vector but does not harden the previewSql SQL-wrapping logic.

Three variant hypotheses were tested against DataEase v2.10.20 (vulnerable) and v2.10.21 (fixed). Variant 3 — a PostgreSQL time-based stacked SQL injection through the same previewSql endpoint — was confirmed as an alternate trigger on v2.10.20, proving the root cause (lack of single-statement validation in previewSql) affects non-MySQL datasources as well. Variants 1 and 2 were partially successful on v2.10.20 but blocked or non-exploitable on v2.10.21. No true bypass of the v2.10.21 patch was found, though Variant 2 exposes a validation-logic bypass (double-URL-encoded allowMultiQueries passes the illegalParameters check while the driver does not recognize it).

Fix Coverage / Assumptions

The original fix (commit 15611593b3631b5a25528b9cdb2ee517ef27929a) assumes that:

  1. Blocking the allowMultiQueries JDBC parameter in Mysql.java is sufficient to prevent multi-statement execution in previewSql.
  2. All MySQL-compatible datasource types (mysql, mariadb, StarRocks, doris, TiDB) parse their configuration through Mysql.class, inheriting the same illegalParameters blocklist.
  3. The previewSql endpoint's datasource-status check (status != "Error") will block any datasource that fails JDBC validation.

The fix does not cover:

  • Other database types whose JDBC drivers support multi-statements natively without requiring a special parameter (e.g., PostgreSQL, SQL Server).
  • The previewSql SQL-wrapping logic itself — there is still no single-statement parser or ;/comment sanitization.
  • Potential bypasses of the illegalParameters string-matching logic (e.g., encoding tricks).

Variant / Alternate Trigger

Variant 1: mariadb type with allowMultiQueries=true
  • Surface: POST /de2api/datasetData/previewSql with a mariadb datasource configured with allowMultiQueries=true.
  • Code path: DatasetDataManage.previewSql()ProviderFactory.getProvider("mariadb")CalciteProvider.parseDatasourceConfiguration() parses as Mysql.classMysql.getJdbc() validates illegalParameters.
  • Result on v2.10.20: Datasource saved with status="Success". Stacked SQL injection succeeded (confirmed by successful INSERT INTO repro_test).
  • Result on v2.10.21: Datasource saved with status="Error" — the allowMultiQueries parameter was blocked by the updated illegalParameters list. Same root cause, same surface, blocked by the patch.
Variant 2: Double-URL-encoded allowMultiQueries
  • Surface: MySQL datasource with extraParams=allow%254DultiQueries=true.
  • Code path: Mysql.getJdbc()URLDecoder.decode(jdbcUrl).toLowerCase().contains("allowmultiqueries").
  • Result on both versions: The validation check is bypassed (status="Success") because URLDecoder.decode turns %25 into %, yielding allow%4DultiQueries=true, which does not match allowmultiqueries. However, MySQL Connector/J also performs single-level URL decoding, so the driver sees allow%4DultiQueries=true and does not enable multi-statements. The stacked SQL exploit fails. This is a validation-logic bypass without vulnerability exploitation.
Variant 3: PostgreSQL time-based stacked query
  • Surface: POST /de2api/datasetData/previewSql with a PostgreSQL datasource.

  • Code path: DatasetDataManage.previewSql() builds wrapper SQL via SQLUtils.buildOriginPreviewSql(), translates dialect with Provider.transSqlDialect(), replaces placeholder with user SQL, then executes via CalciteProvider.jdbcFetchResultField()Statement.executeQuery().

  • Result on v2.10.20: Baseline request took 0.03s; stacked payload SELECT 1) AS x; SELECT pg_sleep(5)-- took 5.04s and returned SQL ERROR: Multiple ResultSets were returned by the query. The 5-second delay proves pg_sleep(5) executed as the second statement. This confirms the same root cause (no single-statement validation) is exploitable through PostgreSQL datasources.

  • Result on v2.10.21: No time delay (0.03s–0.05s). The query immediately returned a PostgreSQL syntax error. The stacked query path is blocked on the fixed version, likely due to differences in how the PostgreSQL JDBC driver or Calcite SQL dialect translation handles the malformed wrapper in this build.

  • Package/component affected: DataEase DatasetDataManage.previewSql() / CalciteProvider — affects all database types that support multi-statement execution.

  • Affected versions: <= v2.10.20 (confirmed on v2.10.20 commit ba0052aff05d85b5ae6e81f687b777b242222dd4).

  • Fixed versions: v2.10.21 (commit e1085ffb75f42b6aca117edf36b30276bfdfe9aa) blocks the MySQL-specific vector but does not harden the previewSql SQL-wrapping logic.

  • Risk level: High (same CVSS 3.1: 8.8) for unpatched instances using PostgreSQL datasources.

  • Consequences: Authenticated attacker can execute arbitrary stacked SQL against any datasource whose driver supports multi-statements, potentially affecting tables, permissions, or application state.

Root Cause

The root cause is identical to CVE-2026-40900:

  1. DatasetDataManage.previewSql() wraps raw user SQL in a subquery (SELECT * FROM ( <USER_SQL> ) tmp LIMIT 100) without parsing or validating that the input is a single SELECT statement.
  2. When the underlying JDBC driver supports multi-statement execution, the attacker can inject ); <SECOND_STATEMENT> <COMMENT> to break out of the wrapper and execute arbitrary side-effecting SQL.

The fix only addresses the prerequisite (allowMultiQueries=true in MySQL) rather than the root cause (missing single-statement validation). Other database types (e.g., PostgreSQL) whose drivers support multi-statements by default remain potentially vulnerable on unpatched versions.

Reproduction Steps

See vuln_variant/reproduction_steps.sh for the automated end-to-end reproduction.

At a high level:

  1. Start DataEase v2.10.20 + MySQL + PostgreSQL via Docker Compose.
  2. Log in as admin / DataEase@123456 (RSA-encrypted credentials fetched via /de2api/dekey).
  3. Create a PostgreSQL datasource (type=pg, host pg, port 5432, database dataease).
  4. Send POST /de2api/datasetData/previewSql with a base64-encoded stacked-SQL payload:
    SELECT 1) AS x; SELECT pg_sleep(5)--
    
  5. Observe the response takes ~5 seconds (baseline is <0.1s), confirming the second statement executed.
  6. On v2.10.21, repeat the same request and observe immediate failure with no time delay, confirming the variant is blocked.

Evidence

  • logs/variant3_v2.10.20_baseline.json — baseline previewSql response against PostgreSQL (elapsed: 0.03s, code: 0).
  • logs/variant3_v2.10.20_exploit.json — stacked pg_sleep(5) payload response (elapsed: 5.04s, error: "Multiple ResultSets were returned by the query.").
  • logs/variant3_v2.10.21_exploit.json — same payload on fixed version (elapsed: 0.03s, error: PostgreSQL syntax error).
  • logs/variant1_v2.10.20_create.jsonmariadb datasource with allowMultiQueries=true saved as status=Success.
  • logs/variant1_v2.10.20_exploit.json — successful stacked SQL injection through mariadb datasource.
  • logs/variant2_v2.10.21_create.json — MySQL datasource with allow%254DultiQueries=true saved as status=Success (validation bypassed).

Recommendations / Next Steps

  1. Add server-side SQL-structure validation in previewSql (defense-in-depth). Before wrapping user SQL, parse it with a SQL parser (e.g., JSqlParser or Calcite SqlParser) and reject any input that:

    • Contains more than one top-level statement (; outside quotes/comments).
    • Contains comment sequences (--, /*, #, etc.) that could swallow the wrapper suffix.
    • Is not a SELECT statement.
  2. Extend illegalParameters validation robustness:

    • Perform iterative URL decoding (up to 3–5 rounds) before matching, or use a whitelist approach for allowed parameters instead of a blacklist.
    • Add Normalizer.normalize() (NFKC) to defeat Unicode homoglyph attacks.
  3. Audit other datasource types for multi-statement support. PostgreSQL and SQL Server drivers support multi-statements natively. Consider adding driver-specific restrictions or, better, adding the universal SQL-structure validation described above.

  4. Regression test: Include stacked-SQL payloads for multiple database types (MySQL, PostgreSQL, SQL Server) in the CI pipeline for previewSql.

Additional Notes

  • Idempotency: The script was run multiple times (8 iterations) with consistent results. Cleanup removes Docker volumes and containers via docker compose down -v and docker volume rm.
  • Limitations: Variant 2 bypasses the illegalParameters check but does not yield a working exploit because MySQL Connector/J does not double-decode %254D. A custom driver or future driver change could potentially close this gap.
  • Trust boundary: All variants require authenticated access to the DataEase previewSql endpoint (same as the original CVE).

CVE-2026-40900 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:001:25
0:00
session startedaccounts/fireworks/models/kimi-k2p6 · cve-2026-40900 · cve-2026
0:02
0:02
web search
0:02
error

Unknown error

0:02
0:02
error

Unknown error

0:41
0:41
extract_facts
no facts extracted
0:41
error

Unknown error

1:05
1:05
extract_facts
no facts extracted
1:12
1:12
1:12
supportrepro
1:21
1:21
1:21
1:23
1:23
1:23
1:23
1:24
1:24
1:24
1:25

Artifacts and Evidence for CVE-2026-40900

Scripts, logs, diffs, and output captured during the reproduction.

bundle/context.json4.7 KB
bundle/metadata.json0.8 KB
bundle/ticket.md7.1 KB
bundle/repro/my.cnf0.1 KB
bundle/repro/init.sql0.1 KB
bundle/repro/rca_report.md5.5 KB
bundle/repro/patch_analysis.md3.1 KB
bundle/repro/docker-compose.yml1.0 KB
bundle/repro/application.yml0.6 KB
bundle/repro/reproduction_steps.sh11.9 KB
bundle/repro/validation_verdict.json1.5 KB
bundle/vuln_variant/root_cause_equivalence.json1.6 KB
bundle/vuln_variant/rca_report.md8.9 KB
bundle/vuln_variant/patch_analysis.md4.1 KB
bundle/vuln_variant/docker-compose.yml1.4 KB
bundle/vuln_variant/variant_manifest.json3.2 KB
bundle/vuln_variant/runtime_manifest.json1.0 KB
bundle/vuln_variant/reproduction_steps.sh12.3 KB
bundle/vuln_variant/validation_verdict.json4.0 KB
bundle/vuln_variant/source_identity.json0.8 KB
bundle/logs/variant3_v2.10.21_create.json0.9 KB
bundle/logs/variant1_v2.10.20_exploit.json0.8 KB
bundle/logs/variant3_v2.10.21_baseline.json0.8 KB
bundle/logs/variant2_v2.10.20_exploit.json0.3 KB
bundle/logs/variant_run.log4.2 KB
bundle/logs/variant_run7.log2.7 KB
bundle/logs/variant3_v2.10.20_exploit.json0.1 KB
bundle/logs/variant3_v2.10.21_exploit.json0.2 KB
bundle/logs/variant_run5.log0.9 KB
bundle/logs/variant_run4.log0.9 KB
bundle/logs/v2.10.20_validate.json0.6 KB
bundle/logs/variant3_v2.10.20_baseline.json0.8 KB
bundle/logs/variant_run3.log0.8 KB
bundle/logs/variant2_v2.10.21_exploit.json0.3 KB
bundle/logs/variant_run2.log0.8 KB
bundle/logs/v2.10.21_create_datasource.json0.9 KB
bundle/logs/variant1_v2.10.20_create.json0.9 KB
bundle/logs/variant_v2.10.21_docker.log0.6 KB
bundle/logs/v2.10.21_exploit.json0.0 KB
bundle/logs/variant2_v2.10.20_create.json0.9 KB
bundle/logs/variant_v2.10.20_docker.log0.6 KB
bundle/logs/variant2_v2.10.21_create.json0.9 KB
bundle/logs/v2.10.21_validate.json0.1 KB
bundle/logs/variant1_v2.10.21_create.json0.9 KB
bundle/logs/v2.10.20_exploit.json0.7 KB
bundle/logs/variant3_v2.10.20_create.json0.9 KB
bundle/logs/variant_run6.log2.7 KB
bundle/logs/variant_run8.log2.8 KB
08 · How to Fix

How to Fix CVE-2026-40900

Upgrade dataease · github to v2.10.21 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-40900 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-40900

How does the CVE-2026-40900 exploit work?

When the datasource's MySQL JDBC URL has allowMultiQueries=true, an attacker submits a payload such as SELECT 1 FROM dual) AS x; INSERT INTO core_msg_type (id, name, pid) VALUES (999999999,'pwned-by-cve-2026-40900',0)#. The closing parenthesis and semicolon escape the wrapping subquery, the INSERT executes as a second stacked statement, and the trailing # comments out the rest of the wrapper.

Which versions of DataEase are affected by CVE-2026-40900, and where is it fixed?

DataEase <= v2.10.20 is affected. It is fixed in v2.10.21.

How severe is CVE-2026-40900?

High severity, CVSS 8.8 per the advisory. An authenticated attacker gains read/write access to the DataEase application database, including inserting rows into tables such as core_msg_type.

How can I reproduce CVE-2026-40900?

Download the verified script from this page and run it in an isolated environment against DataEase <= v2.10.20 configured with a MySQL datasource using allowMultiQueries=true. Submit the crafted stacked-query payload to previewSql and confirm the injected INSERT executes; confirm v2.10.21 blocks it.
11 · References

References for CVE-2026-40900

Authoritative sources for CVE-2026-40900 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.