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-65321-pyathena — SQL injection in PyAthena via DefaultParameterFormatter (CVE-2026-65321) | Kitploit
Tools/GitHubGitHub/rahulreddykarne/cve-2026-65321-pyathena
Vulnerability AnalysisExploitationCloud SecurityLearning & EducationDatabase Security
GitHubrahulreddykarne/cve-2026-65321-pyathena

CVE-2026-65321-pyathena

SQL injection in PyAthena via DefaultParameterFormatter (CVE-2026-65321)

View Repository
21 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-65321: SQL Injection in PyAthena via Backslash Quote-Escaping for Non-SELECT Statements

Severity: Critical, CVSS v4.0 9.3 / CVSS v3.1 9.8 (assigned by VulnCheck, the CNA)

Vector (v4.0): CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Vector (v3.1): CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Affected: PyAthena <= 3.35.3 (all versions through 3.35.3)

Fixed in: 3.35.4

CWE: CWE-89 (Improper Neutralization of Special Elements used in an SQL Command, 'SQL Injection')

Reported by: Rahul Karne

CNA: VulnCheck

Published: August 3, 2026


Summary

PyAthena escaped untrusted input correctly in SELECT queries and incorrectly in queries.

DELETE

PyAthena, the widely used Python DB-API client for Amazon Athena, selects its string-escaping routine from the statement's leading keyword. Statements beginning with SELECT, WITH, INSERT, UPDATE, or MERGE receive Trino-correct escaping, in which a single quote is neutralized by doubling it (''). Every other statement, most commonly a DELETE or a CREATE TABLE … AS SELECT (CTAS), falls through to Hive-style backslash escaping (\'). Athena's engine is Trino, which treats a backslash inside a single-quoted string as an ordinary character, so backslash escaping neutralizes nothing. An attacker who can influence a string parameter in such a statement can terminate the literal and inject arbitrary SQL, with no authentication and no user interaction.

The flaw is therefore absent from the read path and present in exactly the destructive statement types where it does the most damage. The package is pulled 22.3 million times a month.

PyAthena is a third-party community client library for Amazon Athena. It is not an AWS product, and this is not a vulnerability in AWS or in Athena itself.

Impact

An attacker who controls a string parameter passed to a vulnerable statement can break out of the intended string literal and alter the statement's logic. The most direct and reliably demonstrable impact is unauthorized data deletion: a payload such as missing' OR 1=1 -- in a DELETE … WHERE token = %(token)s query neutralizes the WHERE predicate and deletes every row the Athena workgroup's IAM role is permitted to delete (for example, all rows of an Iceberg table). Depending on the statement type and the role's permissions, an attacker may also be able to create attacker-defined tables via CTAS injection and, where they can subsequently read the resulting table, exfiltrate data from other tables the role can access.

All impact is bounded by the permissions of the Athena workgroup / IAM role the client uses. This is a data-plane injection into Athena's SQL engine; it does not yield code execution on the host running PyAthena, nor compromise of AWS itself.

Who is affected: Applications using PyAthena < 3.35.4 with the default DefaultParameterFormatter (client-side pyformat / named parameter substitution) that (1) construct a statement not starting with SELECT/WITH/INSERT/UPDATE/MERGE, in practice DELETE, CTAS, CREATE VIEW, DROP, or ALTER, and (2) pass attacker-influenced data as a string parameter to that statement.

Who is not affected:

  • Anyone on PyAthena 3.35.4 or later.
  • Applications whose parameterized statements only ever begin with SELECT/WITH/INSERT/UPDATE/MERGE, these route to the safe quote-doubling escaper.
  • Applications that pass untrusted values only through Athena's native server-side query parameters rather than PyAthena's client-side interpolation.
  • Applications that never pass untrusted or attacker-influenced data as parameters (all parameters are trusted constants).

Reach

MetricValueSource
Downloads, all-time740.6Mpepy.tech/projects/pyathena
Downloads, last 30 days22.3Mpepy.tech
Downloads, last 24 hours221.0Kpepy.tech
Sustained install rate8.95/secondpepy.tech
Notable downstreamdbt-athena imports _escape_hive and _escape_presto from pyathena.formatter directlyconnections_legacy.py#L23-L27

Technical detail

Root cause

DefaultParameterFormatter.format() selects the string-escaping function purely from the statement's leading keyword. Only an allowlist of prefixes receives the Trino-correct escaper; every other statement falls through to Hive-style backslash escaping.

root@kitploit:~
# src/pyathena/formatter.py, DefaultParameterFormatter.format(), lines ~271-275 (v3.35.2)
operation_upper = operation.upper()
if operation_upper.startswith(("SELECT", "WITH", "INSERT", "UPDATE", "MERGE")):
    escaper = _escape_presto      # safe: doubles single quotes
else:
    escaper = _escape_hive        # UNSAFE for Trino: backslash-escapes quotes
root@kitploit:~
# src/pyathena/formatter.py, lines ~157-165 (v3.35.2)
def _escape_hive(val: str) -> str:
    escaped = (
        val.replace("\\", "\\\\")
        .replace("'", "\\'")          # produces \' (not a quote escape in Trino)
        .replace("\r", "\\r")
        .replace("\n", "\\n")
        .replace("\t", "\\t")
    )
    return f"'{escaped}'"

Amazon Athena's SQL engine is Trino (Presto in earlier engine versions). In Trino, the only escape for a single quote inside a single-quoted string literal is to double it (''); a backslash is a literal character. _escape_hive therefore does not neutralize a quote at all for Athena, it emits ... = 'missing\' OR 1=1 -- ', which Trino parses as the string literal 'missing\' followed by OR 1=1 -- ', i.e. attacker-controlled SQL.

The design is fail-dangerous: it allowlists the safe path and defaults everything else to the unsafe escaper. The upstream fix inverts this to fail-safe (default to the Trino escaper; use Hive escaping only for genuine Hive DDL such as CREATE DATABASE/DROP TABLE/MSCK REPAIR, while treating CTAS and CREATE VIEW as Trino), and additionally strips leading SQL comments so a /* … */ DELETE … prefix cannot defeat statement-type detection.

Why this survived automated analysis

_escape_hive is not missing sanitization, it is sanitization. It is a correct, well-formed escaping routine for Hive's string-literal grammar, applied to an engine that uses Trino's. Taint-tracking tools model SQL injection as untrusted data reaching a sink without passing through an escaper; here the data passes through an escaper on every path, and the escaper looks exactly like remediation code because it is remediation code, for the wrong dialect.

Dialect correctness is not a taint property, so no taint rule evaluates it. The defect is structurally invisible to CodeQL, Semgrep, Snyk, and Socket rather than merely overlooked by them, which is why it persisted in a package installed roughly nine times per second.

Exploitation preconditions

An attacker needs:

  1. A target application using PyAthena < 3.35.4 with the default client-side parameter formatter (pyformat / named paramstyle).
  2. A code path that builds a statement not beginning with SELECT/WITH/INSERT/UPDATE/MERGE, in practice DELETE or CTAS.
  3. The ability to influence a string parameter passed to that statement.
  4. An Athena workgroup / IAM role whose permissions make the injected SQL meaningful (e.g. delete rights on the target table, or read rights on other tables for the exfil path).

Numeric parameters, and any statement routed to the safe escaper, are not exploitable via this flaw.

Proof of concept

The PoC calls the real, unmodified PyAthena formatter (imported from the published PyPI release, not a reconstruction) and executes its output against a local in-memory DuckDB database. No AWS account, no credentials, no network access. Full reproduction is two commands:

root@kitploit:~
pip install pyathena==3.35.2 duckdb
python poc_pyathena_cna_demo.py --no-pause

Source: poc_pyathena_cna_demo.py Recorded demo: Watch the demo

The library's own claim

DefaultParameterFormatter's docstring states that it escapes parameters to prevent SQL injection. The PoC prints that docstring, then prints _escape_presto, _escape_hive, and the prefix-selection branch directly from the installed package via inspect.getsource, so the reader sees the contradiction in the library's own source rather than taking the advisory's word for it.

Impact A/I: DELETE predicate breakout

Attacker-controlled parameter: missing' OR 1=1 --

root@kitploit:~
DELETE FROM sessions WHERE token = 'missing\' OR 1=1 -- '

Trino's lexer recognizes exactly one escape for a single quote inside a single-quoted string literal: doubling it (''). A backslash carries no escaping meaning. The literal therefore terminates at the quote following missing\, and OR 1=1 -- is parsed as SQL. DuckDB shares this property, and against a seeded two-row sessions table the result is:

root@kitploit:~
Rows before executing generated SQL: 2
Rows after executing generated SQL:  0

The WHERE predicate is neutralized and every row is deleted.

Impact C: CTAS exfiltration breakout

Attacker-controlled parameter: nobody' UNION SELECT secret FROM admin_credentials --

root@kitploit:~
CREATE TABLE leaked AS SELECT name FROM users WHERE name = 'nobody\' UNION SELECT secret FROM admin_credentials -- '

The injected UNION copies a row out of a table the original statement never referenced. In the demo, DEMO_SECRET_VALUE from admin_credentials lands in the attacker-visible leaked table. On Athena this is bounded by what the workgroup's IAM role can read.

Controls, the safe path behaves correctly

The same payloads routed through SELECT and UPDATE reach _escape_presto and are correctly neutralized by quote doubling:

root@kitploit:~
SELECT name FROM users WHERE name = 'nobody'' UNION SELECT secret FROM admin_credentials -- '
UPDATE update_control SET token = 'x'' OR 1=1 -- ' WHERE id = 999

Both payloads stay inside the string literal. SELECT returns zero rows and UPDATE changes zero rows, no breakout. These controls establish that the harness is sound and that the defect is specific to escaper selection, not to the test setup.

Patched version 3.35.4

The same three payloads against 3.35.4 all produce doubled-quote output:

root@kitploit:~
DELETE FROM sessions WHERE token = 'missing'' OR 1=1 -- '
CREATE TABLE leaked AS SELECT name FROM users WHERE name = 'nobody'' UNION SELECT secret FROM admin_credentials -- '

The fix also survives a leading-comment prefix, which would otherwise defeat statement-type detection:

root@kitploit:~
/* hi */ DELETE FROM sessions WHERE token = 'missing'' OR 1=1 -- '

In every case the payload is contained as data and no injection occurs.

Remediation

Upgrade to PyAthena 3.35.4 or later:

root@kitploit:~
pip install --upgrade "pyathena>=3.35.4"

If you cannot upgrade immediately: avoid passing untrusted data as parameters to any statement that does not begin with SELECT/WITH/INSERT/UPDATE/MERGE. For destructive statements, validate/allowlist input server-side or perform the operation through a path that does not rely on the client-side formatter. There is no configuration flag that changes the escaper selection in affected versions; upgrading is the reliable fix.

Note for projects that import the escapers directly. The 3.35.4 fix changes escaper selection inside DefaultParameterFormatter.format(). It does not change _escape_hive itself, which remains correct-for-Hive and wrong-for-Trino by design. Any downstream project that imports _escape_hive or _escape_presto from pyathena.formatter and performs its own statement-type dispatch is therefore not remediated by upgrading PyAthena, and should audit its own dispatch logic against the same dialect question.

How to check whether you are affected:

root@kitploit:~
pip show pyathena          # check the installed version
pip-audit                  # flags CVE-2026-65321 once it propagates to the advisory feeds

On the CVSS score

VulnCheck (the CNA) published two scores, both Critical: CVSS v4.0 = 9.3 (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N) and CVSS v3.1 = 9.8 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H).

The attack is remote and unauthenticated with no user interaction (AV:N/PR:N/UI:N) and needs no special attacker-side preconditions (AC:L/AT:N). Impact on the vulnerable system is high across confidentiality, integrity, and availability (VC:H/VI:H/VA:H in v4.0; C:H/I:H/A:H in v3.1): an injected DELETE can destroy data, and an injected CTAS/UNION SELECT can read and copy data the workgroup's role can access. In the v4.0 vector the subsequent-system metrics are all None (SC:N/SI:N/SA:N), the flaw is confined to Athena's SQL and authorization boundary and does not yield code execution on the host or a pivot into AWS itself. That SC/SI/SA:N triple is exactly why v4.0 lands at 9.3 rather than a maxed-out 10.0, and it is the honest answer to "does this mean full system compromise?", it does not. The v3.1 score reaches 9.8 because its binary scope flag (S:U/S:C) collapses into a single bit what v4.0 splits across three separate subsequent-system metrics; the two scores are consistent, not contradictory.

One caveat worth stating proactively: real-world exploitability requires the consuming application to route untrusted input into a non-SELECT parameterized statement (DELETE/CTAS/DROP/ALTER), and the concrete blast radius is bounded by the Athena workgroup's IAM permissions. The base score models the reasonable worst case; a least-privilege deployment is affected less severely.

Disclosure timeline

DateEvent
July 19, 2026Vulnerability identified
July 20, 2026Reported to maintainer
July 20, 2026Maintainer acknowledged
July 31, 2026Fix committed
July 31, 2026Patched version 3.35.4 released
August 2, 2026CVE-2026-65321 assigned by VulnCheck
August 3, 2026Public disclosure

Credit

Discovered and reported by Rahul Karne, security researcher and IEEE Senior Member. His research focuses on injection and input-handling flaws in high-dependency open-source packages, prior disclosures include CVEs in confluent-kafka (1.12B downloads), datamodel-code-generator (185M), and the ElementsKit Elementor Addons WordPress plugin (1M+ active installations).

Contact: [email protected] · GitHub: rahulreddykarne

References

  • CVE-2026-65321, NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-65321
  • CVE Record: https://www.cve.org/CVERecord?id=CVE-2026-65321
  • VulnCheck advisory: https://www.vulncheck.com/advisories/pyathena-sql-injection-via-defaultparameterformatter-delete-ctas
  • GitHub Security Advisory: GHSA-xwj5-g6cv-4r5c, https://github.com/pyathena-dev/PyAthena/security/advisories/GHSA-xwj5-g6cv-4r5c
  • Patch commit: https://github.com/pyathena-dev/PyAthena/commit/27901d12245ea722b3b4e211c60e2ade4e7c8efd
  • PyAthena repository: https://github.com/pyathena-dev/PyAthena
  • Download statistics: https://pepy.tech/projects/pyathena

Press

Media inquiries: [email protected]. High-resolution demo recording, PoC, and additional technical detail available on request.

Download Tool