
DuckDB、Snowflake、BigQuery、DeltaLake連携に影響する、動的パーティションキーを介したDagsterデータベースI/Oマネージャーにおける未認証SQLインジェクションを実証するPoCを含む、CVE-2026-41490の詳細な開示。
深刻度: 高 (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 デプロイメントでは認証が不要です。悪意のあるパーティションキーはエスケープされずに SELECT (ロード) と DELETE (クリーンアップ) の両方のクエリに流れ込み、基盤となるウェアハウス (Snowflake、BigQuery、DuckDB、DeltaLake など) に対する SQL インジェクションを引き起こします。
同じヘルパー _static_where_clause が 5 つの 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 のメタデータ DB に保存され、実行時に addDynamicPartition GraphQL ミューテーションを介して追加されます。デフォルトの dagster-webserver デプロイでは GraphQL は認証されていないため、ネットワーク上の攻撃者がパーティションキーをエンドツーエンドで供給できます。
私はチェーンの両端を確認しました。GraphQL ミューテーションは検証なしで任意のキー文字列を受け入れ、そのキーは 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 は修正後に公開。