SEC001: sql-string-building
SQL text built from values at run time
| Code | SEC001 |
| Name | sql-string-building |
| Category | Security (SEC) |
| Default severity | warning |
| Enabled by default | yes |
| Fix available | no |
| ign-lint equivalent | none |
What it does
Section titled “What it does”Reports SQL text passed to system.db.runQuery, runUpdateQuery,
runScalarQuery, runSFUpdateQuery and to the prepared-statement
functions runPrepQuery, runPrepUpdate, runScalarPrepQuery and
runSFPrepUpdate (and the hidden runPrepStmt, runPrepStmtGetKey,
runUpdateQueryGetKey) when the text is built with %, +,
.format(...) or .join(...) from values that are not literals.
The functions are recognised through imports and aliases (db = system.db, from system.db import runQuery). The query is the first
argument or the query keyword. When it is a local name, every assignment
that reaches the call is followed (q = "... '%s'" % name and q += ...
before system.db.runQuery(q)); the finding points at the expression that
builds the text.
Text built only from literals is fine: concatenated literals, module
constants holding literals, placeholder lists such as ",".join(["?"] * len(ids)), and % formatting whose conversions are all numeric (%d,
%i, %f, ...), which cannot carry quotes.
The prepared-statement functions are included on purpose: their ?
placeholders only protect the values passed as arguments, not values
pasted into the SQL text itself.
Why is this bad?
Section titled “Why is this bad?”Values pasted into SQL text can change the statement (SQL injection), and
quotes or special characters in ordinary data (a name such as O'Brien)
break it. Prepared statements pass the values separately, and the
database driver also handles types and date formats.
Table or column names chosen at run time cannot be passed as ?
arguments; check them against a fixed list and suppress the finding with
# iglint: ignore[SEC001] on that line.
Example
Section titled “Example”query = "SELECT * FROM orders WHERE line = '%s'" % linerows = system.db.runQuery(query)Use instead:
rows = system.db.runPrepQuery("SELECT * FROM orders WHERE line = ?", [line])Generated from the rule metadata by iglint generate-docs; iglint rule SEC001 prints the same page in the terminal. Source: docs/rules/SEC001.md.