sqlalchemy.text() is the escape hatch for raw SQL in SQLAlchemy. If
you wrap an f-string inside it, you've defeated parameter binding and
re-introduced the SQL injection risk that P001-P004 catch for cursor
calls. Same vulnerability, different surface.
Should fail
from sqlalchemy import text
conn.execute(text(f"SELECT * FROM users WHERE id = {user_id}"))
Should pass
from sqlalchemy import text
conn.execute(
text("SELECT * FROM users WHERE id = :id"),
{"id": user_id},
)
Implementation hints
- libCST rule in
sql_guard/rules/python_rules.py.
- Model after
P001 fstring-in-execute.
- Detect
sqlalchemy.text(<FormattedString>) or text(<FormattedString>).
- Severity:
error.
Estimated LOC: ~30 code + ~25 test.
sqlalchemy.text()is the escape hatch for raw SQL in SQLAlchemy. Ifyou wrap an f-string inside it, you've defeated parameter binding and
re-introduced the SQL injection risk that P001-P004 catch for cursor
calls. Same vulnerability, different surface.
Should fail
Should pass
Implementation hints
sql_guard/rules/python_rules.py.P001 fstring-in-execute.sqlalchemy.text(<FormattedString>)ortext(<FormattedString>).error.Estimated LOC: ~30 code + ~25 test.