Summary
CodeQL's Python taint tracking propagates through list.append, but not through list.extend, list.insert, or += on a list. A security query therefore reports a flow written one way and stays silent on the same flow written another way, where the two differ only in which list-mutation method is used.
I'm reporting the asymmetry rather than the incompleteness: append is clearly modelled, so the other three look like a gap in the same model rather than a deliberate boundary.
Reproducer
Each snippet is the same flow — a request parameter reaching subprocess.call(..., shell=True) — differing only in how the value passes through a list.
# reported
def handler():
user = request.args.get("cmd")
acc = [user]
subprocess.call(acc[0], shell=True)
# reported
def handler():
user = request.args.get("cmd")
acc = []
acc.append(user)
subprocess.call(acc[0], shell=True)
# NOT reported
def handler():
user = request.args.get("cmd")
acc = []
acc.extend([user])
subprocess.call(acc[0], shell=True)
# NOT reported
def handler():
user = request.args.get("cmd")
acc = []
acc.insert(0, user)
subprocess.call(acc[0], shell=True)
# NOT reported
def handler():
user = request.args.get("cmd")
acc = []
acc += [user]
subprocess.call(acc[0], shell=True)
Results
codeql database analyze <db> codeql/python-queries:Security/CWE-078/CommandInjection.ql
| construct |
reported |
acc = [user] |
yes |
acc.append(user) |
yes |
acc.extend([user]) |
no |
acc.extend(other) where other = [user] |
no |
acc.extend([user]) then for x in acc: |
no |
acc.insert(0, user) |
no |
acc += [user] |
no |
Environment
- CodeQL CLI 2.26.2 (bundle
codeql-bundle-osx64), macOS arm64
- query: shipped
Security/CWE-078/CommandInjection.ql, unmodified
- the same asymmetry appears with
Security/CWE-022/PathInjection.ql and Security/CWE-089/SqlInjection.ql
Controls
acc = [user] and acc.append(user) are reported, so the query, source and sink all work on these files.
- A variant where the value comes from a local constant instead of
request.args is not reported, so the rule is source-dependent rather than firing on shape.
- All files were present in the database source archive, so the silences are misses rather than unanalysed files.
Note
append in Go is tracked as #14116. This is the Python analogue for the other three mutation forms.
Summary
CodeQL's Python taint tracking propagates through
list.append, but not throughlist.extend,list.insert, or+=on a list. A security query therefore reports a flow written one way and stays silent on the same flow written another way, where the two differ only in which list-mutation method is used.I'm reporting the asymmetry rather than the incompleteness:
appendis clearly modelled, so the other three look like a gap in the same model rather than a deliberate boundary.Reproducer
Each snippet is the same flow — a request parameter reaching
subprocess.call(..., shell=True)— differing only in how the value passes through a list.Results
codeql database analyze <db> codeql/python-queries:Security/CWE-078/CommandInjection.qlacc = [user]acc.append(user)acc.extend([user])acc.extend(other)whereother = [user]acc.extend([user])thenfor x in acc:acc.insert(0, user)acc += [user]Environment
codeql-bundle-osx64), macOS arm64Security/CWE-078/CommandInjection.ql, unmodifiedSecurity/CWE-022/PathInjection.qlandSecurity/CWE-089/SqlInjection.qlControls
acc = [user]andacc.append(user)are reported, so the query, source and sink all work on these files.request.argsis not reported, so the rule is source-dependent rather than firing on shape.Note
appendin Go is tracked as #14116. This is the Python analogue for the other three mutation forms.