严重性: 严重,CVSS v4.0 9.3 / CVSS v3.1 9.8(由 CNA VulnCheck 分配)
向量(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
向量(v3.1): CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
受影响版本: PyAthena <= 3.35.3(直至 3.35.3 的所有版本)
修复版本: 3.35.4
CWE: CWE-89(对 SQL 命令中使用的特殊元素的不当中和,即“SQL 注入”)
报告者: Rahul Karne
CNA: VulnCheck
发布时间: 2026 年 8 月 3 日
PyAthena 在 SELECT 查询中正确转义了不受信任的输入,而在 DELETE
查询中转义不正确。
PyAthena 是广泛使用的 Amazon Athena Python DB-API 客户端,它根据语句的
开头关键字选择其字符串转义例程。以 SELECT、WITH、INSERT、UPDATE
或 MERGE 开头的语句会采用 Trino 正确的转义方式,即通过将单引号加倍
('')来中和。所有其他语句(最常见的是 DELETE 或
CREATE TABLE … AS SELECT(CTAS))都会落入 Hive 风格的反斜杠转义
(\')。Athena 的引擎是 Trino,它将单引号字符串中的反斜杠视为普通字符,
因此反斜杠转义实际上无法中和任何内容。能够在此类语句中影响字符串参数的
攻击者可以终止字面量并注入任意 SQL,无需任何身份验证,也无需用户交互。
因此,该缺陷在读取路径上不存在,而恰恰存在于造成最大破坏的破坏性语句 类型中。该包每月被下载 2230 万次。
PyAthena 是 Amazon Athena 的第三方社区客户端库。它不是 AWS 产品, 这不是 AWS 或 Athena 本身的漏洞。
控制传入易受影响语句的字符串参数的攻击者可以逃逸出预期的字符串字面量并
改变语句的逻辑。最直接且可稳定证明的影响是未经授权的数据删除:在
DELETE … WHERE token = %(token)s 查询中,诸如 missing' OR 1=1 -- 之类的
载荷会中和 WHERE 谓词,并删除 Athena 工作组的 IAM 角色有权删除的每一行
(例如 Iceberg 表的所有行)。根据语句类型和角色权限,攻击者还可能通过
CTAS 注入创建攻击者定义的表,并且在随后能够读取结果表的情况下,从角色
可访问的其他表中窃取数据。
所有影响都受客户端使用的 Athena 工作组 / IAM 角色权限的约束。这是对 Athena SQL 引擎的数据平面注入;它不会在运行 PyAthena 的主机上产生代码执行, 也不会危及 AWS 本身。
受影响对象: 使用 PyAthena < 3.35.4 且采用默认
DefaultParameterFormatter(客户端 pyformat / named 参数替换)的应用程序,
这些应用程序 (1) 构造不以 SELECT/WITH/INSERT/UPDATE/MERGE 开头的
语句,实际为 DELETE、CTAS、CREATE VIEW、DROP 或 ALTER,并且 (2) 将
受攻击者影响的数据作为字符串参数传递给该语句。
不受影响的对象:
3.35.4 或更高版本的用户。SELECT/WITH/INSERT/UPDATE/MERGE 开头的应用程序,
这些语句会路由到安全的引号加倍转义器。DefaultParameterFormatter.format() 仅根据语句的开头关键字选择字符串转义
函数。只有允许列表中的前缀才会使用 Trino 正确的转义器;所有其他语句都会
落入 Hive 风格的反斜杠转义。
# 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
# 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 的 SQL 引擎是 Trino(早期引擎版本为 Presto)。在 Trino 中,
单引号字符串字面量内单个引号的唯一转义方式是将其加倍('');反斜杠是
普通字符。因此,对于 Athena,_escape_hive 根本无法中和引号,它会输出
... = 'missing\' OR 1=1 -- ',Trino 会将其解析为字符串字面量
'missing\' 后跟 OR 1=1 -- ',也就是攻击者可控的 SQL。
该设计采用危险失效(fail-dangerous)策略:它将安全路径列入允许列表,而将
所有其他情况默认为不安全的转义器。上游修复将其反转为故障安全(fail-safe)
策略(默认使用 Trino 转义器;仅对真正的 Hive DDL(如 CREATE DATABASE/
DROP TABLE/MSCK REPAIR)使用 Hive 转义,同时将 CTAS 和 CREATE VIEW
视为 Trino 语句),并且额外剥离了开头的 SQL 注释,使 /* … */ DELETE …
前缀无法绕过语句类型检测。
_escape_hive 并非缺少净化,它就是净化。对于 Hive 的字符串字面量语法
来说,它是一个正确且格式良好的转义例程,只是被应用到了使用 Trino 语法的
引擎上。污点跟踪工具将 SQL 注入建模为不受信任的数据未经转义器处理就到达
接收器(sink);而这里的数据在每条路径上都经过了转义器,且该转义器看起来
完全就是修复代码,因为它确实是修复代码,只是针对的是错误的方言。
方言正确性不是污点属性,因此没有任何污点规则会评估它。该缺陷对 CodeQL、 Semgrep、Snyk 和 Socket 而言是结构性不可见的,而不仅仅是未被发现,这就是 为什么它会长期存在于一个大约每秒被安装九次的包中。
攻击者需要:
< 3.35.4 且采用默认客户端参数格式化器(pyformat /
named 参数风格)的目标应用程序。SELECT/WITH/INSERT/UPDATE/MERGE 开头的语句的
代码路径,实际为 DELETE 或 CTAS。数值参数以及任何路由到安全转义器的语句,都无法通过此缺陷被利用。
该 PoC 调用真实、未修改的 PyAthena 格式化器(从已发布的 PyPI 版本 导入,而非重新构造),并针对本地内存中的 DuckDB 数据库执行其输出。无需 AWS 账户、无需凭据、无需网络访问。完整复现只需两条命令:
pip install pyathena==3.35.2 duckdb
python poc_pyathena_cna_demo.py --no-pause
源码:poc_pyathena_cna_demo.py
录制的演示:观看演示
DefaultParameterFormatter 的文档字符串(docstring)声明它会转义参数以防止
SQL 注入。PoC 会打印该文档字符串,然后通过 inspect.getsource 直接从已安装
的包中打印 _escape_presto、_escape_hive 以及前缀选择分支,让读者亲眼
看到库自身源码中的矛盾,而不是仅凭此公告的一家之言。
DELETE 谓词逃逸攻击者控制的参数:missing' OR 1=1 --
DELETE FROM sessions WHERE token = 'missing\' OR 1=1 -- '
Trino 的词法分析器对单引号字符串字面量内的单引号只识别一种转义方式:将
其加倍('')。反斜杠没有任何转义含义。因此该字面量会在 missing\ 之后
的引号处终止,而 OR 1=1 -- 会被解析为 SQL。DuckDB 具有相同的属性,
针对预先植入两行数据的 sessions 表,结果为:
Rows before executing generated SQL: 2
Rows after executing generated SQL: 0
WHERE 谓词被中和,所有行都被删除。
攻击者控制的参数:nobody' UNION SELECT secret FROM admin_credentials --
CREATE TABLE leaked AS SELECT name FROM users WHERE name = 'nobody\' UNION SELECT secret FROM admin_credentials -- '
注入的 UNION 会从原始语句从未引用的表中复制出一行。在演示中,来自
admin_credentials 的 DEMO_SECRET_VALUE 落入了攻击者可见的 leaked 表。
在 Athena 上,这受工作组 IAM 角色可读取内容的限制。
相同的载荷通过 SELECT 和 UPDATE 路由时会到达 _escape_presto,并通过
引号加倍被正确中和:
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
两个载荷都保持在字符串字面量内部。SELECT 返回零行,UPDATE 更改零行,
没有逃逸。这些对照组证明测试框架是健全的,且该缺陷特定于转义器选择,
而非测试设置。
针对 3.35.4 的相同三个载荷都会产生引号加倍输出:
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 -- '
该修复还能抵御开头注释前缀,否则这种前缀会绕过语句类型检测:
/* hi */ DELETE FROM sessions WHERE token = 'missing'' OR 1=1 -- '
在所有情况下,载荷都被作为数据包含,不会发生注入。
升级到 PyAthena 3.35.4 或更高版本:
pip install --upgrade "pyathena>=3.35.4"
如果无法立即升级: 避免将不受信任的数据作为参数传递给任何不以
SELECT/WITH/INSERT/UPDATE/MERGE 开头的语句。对于破坏性语句,请在
服务端验证/允许列表输入,或通过不依赖客户端格式化器的路径执行操作。受影响
版本中没有任何配置标志可以改变转义器选择;升级才是可靠的修复方式。
给直接导入转义器的项目的说明。 3.35.4 的修复更改了
DefaultParameterFormatter.format() 内部的转义器选择。它并没有改变
_escape_hive 本身,后者按设计仍然是“对 Hive 正确、对 Trino 错误”。
因此,任何从 pyathena.formatter 导入 _escape_hive 或 _escape_presto
并自行进行语句类型分发的下游项目,不会因为升级 PyAthena 而得到修复,
应针对相同的方言问题审计自己的分发逻辑。
如何检查自己是否受影响:
pip show pyathena # check the installed version
pip-audit # flags CVE-2026-65321 once it propagates to the advisory feeds
VulnCheck(CNA)发布了两个评分,均为严重: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)和
CVSS v3.1 = 9.8(CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)。
该攻击是远程、未认证的,且无需用户交互(AV:N/PR:N/UI:N),也不需要在
攻击者侧具备特殊前置条件(AC:L/AT:N)。对易受影响系统在机密性、完整性
和可用性方面的影响均为高(v4.0 中为 VC:H/VI:H/VA:H;v3.1 中为
C:H/I:H/A:H):注入的 DELETE 可以销毁数据,注入的 CTAS/UNION SELECT
可以读取和复制工作组角色可访问的数据。在 v4.0 向量中,后续系统指标均为
None(SC:N/SI:N/SA:N),该缺陷局限于 Athena 的 SQL 和授权边界,不会
在主机上产生代码执行,也不会借此入侵 AWS 本身。正是 SC/SI/SA:N 这一组合
使得 v4.0 落在 9.3 而不是满分的 10.0,这也是对“这是否意味着系统完全
沦陷?”的诚实回答——并非如此。v3.1 得分达到 9.8,是因为其二元化的范围
标志(S:U/S:C)将 v4.0 分散在三个独立后续系统指标中的内容压缩成了
一个比特;两个评分是一致的,并不矛盾。
有一点值得主动说明的注意事项:实际可利用性要求使用方应用程序将不受信任的
输入路由到非 SELECT 的参数化语句(DELETE/CTAS/DROP/ALTER)中,且
具体的爆炸半径受 Athena 工作组 IAM 权限的约束。基础评分建模的是合理的
最坏情况;最小权限部署受到的影响会较轻。
由 Rahul Karne 发现并报告,他是安全研究员和 IEEE 高级会员。他的研究 专注于高依赖开源包中的注入和输入处理缺陷,此前披露的漏洞包括 confluent-kafka(11.2 亿次下载)、datamodel-code-generator(1.85 亿次)以及 ElementsKit Elementor Addons WordPress 插件(100 万+ 活跃安装)中的 CVE。
联系方式:[email protected] · GitHub:rahulreddykarne
媒体垂询:[email protected]。可应要求提供高清演示录像、PoC 以及 其他技术细节。
| 指标 | 数值 | 来源 |
|---|
| 历史总下载量 | 740.6M | pepy.tech/projects/pyathena |
| 最近 30 天下载量 | 22.3M | pepy.tech |
| 最近 24 小时下载量 | 221.0K | pepy.tech |
| 持续安装速率 | 8.95/秒 | pepy.tech |
| 重要下游项目 | dbt-athena 直接从 pyathena.formatter 导入 _escape_hive 和 _escape_presto | connections_legacy.py#L23-L27 |
| 日期 | 事件 |
|---|
| 2026 年 7 月 19 日 | 发现漏洞 |
| 2026 年 7 月 20 日 | 报告给维护者 |
| 2026 年 7 月 20 日 | 维护者确认 |
| 2026 年 7 月 31 日 | 提交修复 |
| 2026 年 7 月 31 日 | 发布已修复版本 3.35.4 |
| 2026 年 8 月 2 日 | VulnCheck 分配 CVE-2026-65321 |
| 2026 年 8 月 3 日 | 公开披露 |