严重程度:高(CVSS 8.3) CWE:CWE-89 — SQL 注入 受影响版本:Dagster core <= 1.13.0 及集成包 <= 0.29.0 修复版本:Dagster core 1.13.1 及集成包 0.29.1 安全公告:GHSA-mjw2-v2hm-wj34 NVD:https://nvd.nist.gov/vuln/detail/CVE-2026-41490 致谢:Romain Deperne
每个 Dagster 数据库 I/O 管理器都通过 f-string 将分区键值直接插值到 SQL 中来构建其 WHERE 子句。当资产使用 DynamicPartitionsDefinition 时,分区键可以在运行时通过 GraphQL API(addDynamicPartition)设置——而在默认的 webserver 部署中,该 API 是未经身份验证的。恶意分区键会未经转义地流入 SELECT(加载)和 DELETE(清理)查询,从而对底层数据仓库(Snowflake、BigQuery、DuckDB、DeltaLake 等)造成 SQL 注入。
同一个辅助函数 _static_where_clause 被复制粘贴到了五个 I/O 管理器包中。每一个都执行以下操作:
def _static_where_clause(table_partition):
partitions = ", ".join(f"'{partition}'" for partition in table_partition.partitions)
return f"""{table_partition.partition_expr} in ({partitions})"""
partition 被单引号包裹且未做转义。问题在于 partition 是否可能被攻击者控制。对于静态分区,它由开发者定义——并不值得关注。对于 DynamicPartitionsDefinition,其键存储在 Dagster 的元数据数据库中,并在运行时通过 addDynamicPartition GraphQL mutation 添加。在默认的 dagster-webserver 部署中,GraphQL 未经过身份验证,因此网络上的攻击者可以端到端地提供分区键。
我确认了攻击链的两端:GraphQL mutation 接受任意键字符串且不做任何验证,而该键通过 context.asset_partition_keys 原样到达 _static_where_clause。
addDynamicPartition(... partitionKey: "') UNION SELECT username, password_hash FROM secret_table; --")launchRun(...) 以该分区为目标SELECT/DELETE ... WHERE col in ('') UNION SELECT ... ; --')| 包 | 文件 |
|---|---|
| dagster-duckdb | io_manager.py:340-342 |
| dagster-snowflake | snowflake_io_manager.py:434-436 |
| dagster-gcp (BigQuery) | bigquery/io_manager.py:472-474 |
| dagster-deltalake | io_manager.py:265-267 |
| dagster-snowflake-polars | snowflake_polars_type_handler.py:74 |
加载路径和清理路径都会使用它:
query = f"SELECT {col_str} FROM {schema}.{table} WHERE\n" + _partition_where_clause(...) # read
query = f"DELETE FROM {schema}.{table} WHERE\n" + _partition_where_clause(...) # write
分区键原本被视为可信的开发者常量,但 DynamicPartitionsDefinition 将它们变成了运行时可从外部设置的输入。对于静态键而言“安全”的 f-string 插值,对于动态键则变成了注入。修复:使用参数化查询 / 正确的标识符与字面量引用,而不是 f-string。
poc/poc_partition_sqli.py — 展示了良性键与恶意键下存在漏洞的 _static_where_clause 输出,针对已播种的数据库运行实时 DuckDB 基于 UNION 的数据窃取 + DROP TABLE,并打印出攻击者发送的确切 addDynamicPartition / launchRun GraphQL 载荷。
pip install duckdb # minimal; full chain: dagster dagster-duckdb pandas
python3 poc/poc_partition_sqli.py
针对 Dagster 所编排的数据仓库的未认证(默认配置)SQL 注入——可任意读取其他表并进行破坏性写入。Dagster 处于数据平台的核心位置,因此该漏洞可触及技术栈中最敏感的数据存储。
通过 GitHub Security Advisory 负责任地披露。PoC 在修复后发布。