
Dagster 데이터베이스 I/O 관리자의 동적 파티션 키를 통한 인증되지 않은 SQL 인젝션을 PoC로 입증하는 CVE-2026-41490 상세 공개로, DuckDB, Snowflake, BigQuery, DeltaLake 통합에 영향을 미칩니다.
심각도: 높음 (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 관리자는 파티션 키 값을 SQL에 직접 f-string으로 보간하여
WHERE 절을 구성합니다. 에셋이 DynamicPartitionsDefinition을 사용할 때, 파티션 키는 런타임에
GraphQL API(addDynamicPartition)를 통해 설정될 수 있으며 — 이는 기본 웹서버 배포에서
인증이 필요하지 않습니다. 악의적인 파티션 키는 이스케이프되지 않은 채로 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이 공격자의 제어를 받을 수 있는지 여부였습니다. 정적(static) 파티션의 경우 개발자가 정의하므로 흥미롭지 않습니다. 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 |
로드 경로와 정리(cleanup) 경로 모두 이를 사용합니다:
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는 수정 이후 게시됨.