VNX-1094: Excessive Index Range Scan for a Data Resource
Python DB-API code that runs a SELECT over a caller-chosen range (BETWEEN or </>= against placeholders) with no LIMIT or aggregate and then loads every row with fetchall().
| Field | Value |
|---|---|
| Rule ID | VNX-1094 |
| Severity | Low |
| SARIF level | note |
| Kind | sast |
| Languages | Python |
| CWE | CWE-1094 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:L/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L |
| Tags | sql performance resource-consumption cwe-1094 |
| Source | internal/sast/rules/vnx-1094.rego |
Overview
VNX-1094 maps to CWE-1094: Excessive Index Range Scan for a Data Resource. It reports a cursor.execute(...) call whose SQL (inline, triple-quoted, or assigned to a variable a few lines above) is a SELECT with an open range predicate over placeholders (BETWEEN %s AND %s, amount >= ?, ts > :since, %(name)s, $1), with no LIMIT, TOP, FETCH FIRST or aggregate, when fetchall() follows within a few lines.
Why This Matters
The width of the range decides how many index entries are scanned and how many rows are pulled into memory, and here the caller decides it. One request with a wide range becomes a scan of the table and a large in-memory list, which is a cheap way to exhaust a database or a worker.
Not reported: queries with LIMIT/TOP/FETCH FIRST, aggregates (COUNT, SUM, MIN, MAX, AVG), equality predicates, results read with fetchone() or fetchmany(), ORM queries, test files and comments.
What Gets Flagged
cur.execute("SELECT * FROM orders WHERE created_at BETWEEN %s AND %s", (start, end)) # FLAGGED
return cur.fetchall()
sql = "SELECT id, kind FROM events WHERE ts >= %(since)s ORDER BY ts"
cursor.execute(sql, {"since": since}) # FLAGGED
for row in cursor.fetchall():
...
Remediation
- Cap the range on the server side (a maximum span between the bounds) before running the query.
- Add
LIMIT/OFFSETor keyset pagination, or stream withfetchmany(n). - For a confirmed false positive, add a
# vulnetix-ignore: VNX-1094comment on the line.
References
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-1094
// nosec vnx-1094
Or record an ignore rule: vulnetix ignore add --rule vnx-1094 --reason "...". See Suppressing findings.