Security advisory GHSA-mjw2-v2hm-wj34: Dagster Vulnerable to SQL Injection via Dynamic Partition Keys in Database I/O Manager Integrations
Package: dagster-duckdb (pypi), vulnerable version: 0.29.0, fixed in: 0.29.1
CWE: CWE-89
Files changed by the fix:
b/dagster_duckdb/io_manager.py
b/dagster_duckdb/version.py
b/dagster_duckdb_tests/test_io_manager.py

Fix diff:
diff -ruN --no-dereference /home/ubuntu/closed-source-intelligence/data/cache/pypi-sdists/dagster-duckdb-0.29.0/PKG-INFO /home/ubuntu/closed-source-intelligence/data/cache/pypi-sdists/dagster-duckdb-0.29.1/PKG-INFO
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: dagster-duckdb
-Version: 0.29.0
+Version: 0.29.1
 Summary: Package for DuckDB-specific Dagster framework op and resource components.
 Project-URL: Homepage, https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-duckb
 Author-email: Dagster Labs <hello@dagsterlabs.com>
@@ -9,7 +9,7 @@
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 3.10
 Requires-Python: <3.15,>=3.10
-Requires-Dist: dagster==1.13.0
+Requires-Dist: dagster==1.13.1
 Requires-Dist: duckdb
 Provides-Extra: pandas
 Requires-Dist: pandas<3.0.0; extra == 'pandas'
diff -ruN --no-dereference /home/ubuntu/closed-source-intelligence/data/cache/pypi-sdists/dagster-duckdb-0.29.0/dagster_duckdb/io_manager.py /home/ubuntu/closed-source-intelligence/data/cache/pypi-sdists/dagster-duckdb-0.29.1/dagster_duckdb/io_manager.py
--- a/dagster_duckdb/io_manager.py
+++ b/dagster_duckdb/io_manager.py
@@ -13,6 +13,7 @@
     DbTypeHandler,
     TablePartitionDimension,
     TableSlice,
+    static_where_clause,
 )
 from dagster._core.storage.io_manager import dagster_maintained_io_manager
 from dagster._utils.backoff import backoff
@@ -323,7 +324,7 @@
         (
             _time_window_where_clause(partition_dimension)
             if isinstance(partition_dimension.partitions, TimeWindow)
-            else _static_where_clause(partition_dimension)
+            else static_where_clause(partition_dimension)
         )
         for partition_dimension in partition_dimensions
     )
@@ -335,8 +336,3 @@
     start_dt_str = start_dt.strftime(DUCKDB_DATETIME_FORMAT)
     end_dt_str = end_dt.strftime(DUCKDB_DATETIME_FORMAT)
     return f"""{table_partition.partition_expr} >= '{start_dt_str}' AND {table_partition.partition_expr} < '{end_dt_str}'"""
-
-
-def _static_where_clause(table_partition: TablePartitionDimension) -> str:
-    partitions = ", ".join(f"'{partition}'" for partition in table_partition.partitions)
-    return f"""{table_partition.partition_expr} in ({partitions})"""
diff -ruN --no-dereference /home/ubuntu/closed-source-intelligence/data/cache/pypi-sdists/dagster-duckdb-0.29.0/dagster_duckdb/version.py /home/ubuntu/closed-source-intelligence/data/cache/pypi-sdists/dagster-duckdb-0.29.1/dagster_duckdb/version.py
--- a/dagster_duckdb/version.py
+++ b/dagster_duckdb/version.py
@@ -1 +1 @@
-__version__ = "0.29.0"
+__version__ = "0.29.1"
diff -ruN --no-dereference /home/ubuntu/closed-source-intelligence/data/cache/pypi-sdists/dagster-duckdb-0.29.0/dagster_duckdb_tests/test_io_manager.py /home/ubuntu/closed-source-intelligence/data/cache/pypi-sdists/dagster-duckdb-0.29.1/dagster_duckdb_tests/test_io_manager.py
--- a/dagster_duckdb_tests/test_io_manager.py
+++ b/dagster_duckdb_tests/test_io_manager.py
@@ -158,3 +158,39 @@
         == "DELETE FROM schema1.table1 WHERE\nmy_fruit_col in ('apple') AND\nmy_timestamp_col >="
         " '2020-01-02 00:00:00' AND my_timestamp_col < '2020-02-03 00:00:00'"
     )
+
+
+def test_get_select_statement_escapes():
+    assert (
+        DuckDbClient.get_select_statement(
+            TableSlice(
+                schema="schema1",
+                table="table1",
+                partition_dimensions=[
+                    TablePartitionDimension(
+                        partition_expr="my_col",
+                        partitions=["it's a test"],
+                    )
+                ],
+            )
+        )
+        == "SELECT * FROM schema1.table1 WHERE\nmy_col in ('it''s a test')"
+    )
+
+
+def test_get_cleanup_statement_escapes():
+    assert (
+        _get_cleanup_statement(
+            TableSlice(
+                schema="schema1",
+                table="table1",
+                partition_dimensions=[
+                    TablePartitionDimension(
+                        partition_expr="my_col",
+                        partitions=["it's a test"],
+                    )
+                ],
+            )
+        )
+        == "DELETE FROM schema1.table1 WHERE\nmy_col in ('it''s a test')"
+    )
diff -ruN --no-dereference /home/ubuntu/closed-source-intelligence/data/cache/pypi-sdists/dagster-duckdb-0.29.0/pyproject.toml /home/ubuntu/closed-source-intelligence/data/cache/pypi-sdists/dagster-duckdb-0.29.1/pyproject.toml
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,7 +6,7 @@
 
 [project]
 name = "dagster-duckdb"
-version = "0.29.0"
+version = "0.29.1"
 description = "Package for DuckDB-specific Dagster framework op and resource components."
 authors = [
     { name = "Dagster Labs", email = "hello@dagsterlabs.com" },
@@ -19,7 +19,7 @@
 ]
 dependencies = [
     "duckdb",
-    "dagster==1.13.0",
+    "dagster==1.13.1",
 ]
 
 [project.urls]