False positive: AGENT-041 flags agent `.execute()` calls as SQL injection
#10 opened on Jul 4, 2026
Repository metrics
- Stars
- (180 stars)
- PR merge metrics
- (PR metrics pending)
Description
Summary
AGENT-041 (SQL Injection via String Interpolation) over-triggers on any .execute() method call, misclassifying agent-invocation patterns such as agent.execute(task) as SQL-injection sinks. The scanner's taint analysis reports sink_type: "sql_execution" for these calls even when the receiver is not a DB cursor or connection.
Version affected: 0.19.2 (also reproduces on prior releases sharing the same sink-matching logic).
Reproduction
Two-file minimal repro. Both files are scanned in a single invocation on agent-audit 0.19.2.
fp_case.py — should be clean (agent invocation, not SQL):
class Agent:
def execute(self, task):
return task
def delegate_task(target_agent, task):
# This is agent invocation, not SQL execution.
return target_agent.execute(task)
tp_control.py — positive control, should still fire (real SQL sink):
import sqlite3
def search_users(name: str):
conn = sqlite3.connect("app.db")
cursor = conn.cursor()
# Real SQL injection sink (unparameterized f-string).
cursor.execute(f"SELECT * FROM users WHERE name = '{name}'")
return cursor.fetchall()
Command:
agent-audit scan . --format json
Actual output (both flagged, identical confidence and tier):
AGENT-041 @ tp_control.py:10 tier=BLOCK conf=1.0 snippet='cursor.execute(f"SELECT * FROM users WHERE name = \'{name}\'")'
AGENT-041 @ fp_case.py:11 tier=BLOCK conf=1.0 snippet='return target_agent.execute(task)'
The taint-analysis metadata attached to the false-positive finding is explicit about the misclassification:
{
"dangerous_flows": [
{
"var": "task",
"sink": "target_agent.execute",
"sink_type": "sql_execution",
"line": 11,
"path": ["task"],
"confidence": 0.85,
"source": "user_input"
}
],
"sanitization_points": []
}
The scanner has classified target_agent.execute as sql_execution sink, though target_agent is not a DB cursor or connection.
Expected vs Actual
| Case | Expected | Actual (0.19.2) |
|---|---|---|
target_agent.execute(task) (agent invocation) |
Clean | AGENT-041 BLOCK, conf 1.0 |
cursor.execute(f"SELECT ... {x}") (real SQL) |
AGENT-041 finding | AGENT-041 BLOCK, conf 1.0 |
The positive control confirms the rule itself is functionally correct on real SQL sinks — this issue is scoped to over-triggering, not rule regression.
Root cause (preliminary)
The tainted-parameter check that produces this finding is _check_sql_tainted_param in packages/audit/agent_audit/scanners/python_scanner.py (defined at L3595). The only receiver-side gate is a method-name whitelist at L3608:
if simple_name not in ('execute', 'executemany', 'executescript'):
return None
If the method name matches and the first argument is a function parameter (_current_function_params), the check emits a finding with the hard-coded sink_type: 'sql_execution' at L3627. No inspection of the receiver's type, imports, or origin is performed, so any object exposing an .execute(...) method — agent frameworks, task runners, ORM query builders, subprocess wrappers, concurrent.futures.Executor, etc. — is treated as a DB cursor.
The docstring at L3603-3606 confirms the check was written for the cursor.execute(query) pattern (introduced as the KNOWN-008 fix in v0.15.1), but the receiver-type premise was never enforced in code.
More broadly, this is a case where a syntactic signal (the method name .execute) is used as a proxy for a semantic property (the receiver is a SQL execution sink). The two coincide for DB-API cursors but diverge for any other object exposing .execute; resolving it reliably requires receiver-type information the current matcher does not track.
Environment
agent-audit0.19.2(installed viapip install agent-audit==0.19.2from PyPI)- Python 3.14 (also reproduces on 3.9)
- OS: macOS 15 (should be OS-agnostic)
Impact
Any codebase using .execute() as an agent invocation, task dispatch, or framework method — common in multi-agent frameworks (CrewAI, AutoGen, LangGraph, custom orchestrators) — will surface high-confidence BLOCK findings that require manual triage. This inflates FP rate on agent-oriented targets and lowers signal for real SQL sinks.