fix: prevent SQL injection in workflow PGSqlNode #1322
Conversation
Signed-off-by: dongjiang <dongjiang1989@126.com>
There was a problem hiding this comment.
Code Review
This pull request introduces SQL validation and sanitization measures for PostgreSQL nodes, including identifier pattern enforcement, multi-statement blocking, and keyword restriction. It also migrates placeholder replacement to use SQLAlchemy's parameter binding for improved security. Feedback suggests expanding the allowed SQL keywords to include 'WITH' and 'EXPLAIN' to avoid over-restricting valid queries. Furthermore, the use of SQLAlchemy's text() on the full template needs to be reconsidered as it may cause regressions with PostgreSQL type casts, native colons, and quoted placeholders.
| stmt = text(sql).bindparams(**params) | ||
| return str(stmt.compile(compile_kwargs={"literal_binds": True})) |
There was a problem hiding this comment.
Using SQLAlchemy's text() on the entire SQL template introduces several regressions:
- Type Casts: PostgreSQL's double-colon type casts (e.g.,
col::text) will be broken because SQLAlchemy interprets::as an escaped parameter, resulting in a single colon in the output (e.g.,col:text), which is invalid syntax. - Unbound Parameters: If the user's SQL contains colons that are not intended as parameters (e.g., in a string literal or a native database parameter like
:name), SQLAlchemy will attempt to bind them. Since they aren't in theparamsdictionary, the compilation will fail with aCompileErrororKeyError. - Quoted Placeholders: Placeholders wrapped in quotes in the template (e.g.,
'{{var}}') will not be substituted because SQLAlchemy does not perform parameter binding inside string literals. The resulting SQL will literally contain the string:p_0. - Dialect Specifics: Compiling with the default dialect may lead to incorrect escaping of literals. It is safer to explicitly use the PostgreSQL dialect (e.g.,
stmt.compile(dialect=postgresql.dialect(), ...)).
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: dongjiang <dongjiang2010@gmail.com>
|
/cc @hygao1024 PTAL |
|
Hi developer, The database node in the workflow mainly serves as a carrier for invoking Therefore, this issue is recommended to be enhanced at the |
Summary
validate_sql_template()to restrict CUSTOM mode to safe DML operations (SELECT/INSERT/UPDATE/DELETE/CALL), block multi-statement SQL and dangerous keywords (DROP, ALTER, TRUNCATE,etc.)
replace_placeholders()with SQLAlchemy parameterized binding (text()+bindparams()) to prevent SQL injection through user-supplied valuesType of Change
Related Issue
Fixes #1281
Changes
Testing
Screenshots (if applicable)
Checklist