The subprocess standard library module for spawning child processes. Most call APIs accept either a list[str] (safe) or a string with shell=True (command-injection sink when the string contains user input).
.run().call().check_call().check_output().Popen()from codepathfinder.python_decorators import python_rule
from codepathfinder import calls, flows
from codepathfinder.presets import PropagationPresets
@python_rule(
id="PYTHON-CMDI-001",
name="Command injection via subprocess with shell=True",
severity="CRITICAL",
category="command-execution",
cwe="CWE-78",
owasp="A03:2021",
message="User input flows into subprocess with shell=True. Pass args as a list and avoid shell=True.",
)
def detect_subprocess_shell_injection():
return flows(
from_sources=[
calls("request.args.get", "request.form.get", "request.get_json"),
calls("input"),
],
to_sinks=[
calls("subprocess.run", match_name={"shell": True}).tracks(0),
calls("subprocess.Popen", match_name={"shell": True}).tracks(0),
calls("subprocess.call", match_name={"shell": True}).tracks(0),
calls("subprocess.check_output", match_name={"shell": True}).tracks(0),
],
sanitized_by=[calls("shlex.quote"), calls("shlex.split")],
propagates_through=PropagationPresets.standard(),
scope="global",
)
pathfinder scan --ruleset custom/security --project ..run()Sinksubprocess.run(args, *, shell=False, capture_output=False, ...) -> CompletedProcess
Runs a command and waits for completion. Sink when args is a string with shell=True.
0.call()Sinksubprocess.call(args, *, shell=False, ...) -> int
Runs a command and returns its exit code. Sink under shell=True.
0.check_call()Sinksubprocess.check_call(args, *, shell=False, ...) -> int
Like call() but raises on non-zero exit. Same injection risk.
0.check_output()Sinksubprocess.check_output(args, *, shell=False, ...) -> bytes
Runs a command and returns stdout. Sink under shell=True.
0.Popen()Sinksubprocess.Popen(args, *, shell=False, ...) -> Popen
Low-level process constructor. Sink when args is a string with shell=True.
0| FQN | Field | |
|---|---|---|
| subprocess | fqns[0] |
Wrong FQN → 0 findings. Verify with: change fqns to garbage → must produce 0 results.
from codepathfinder.go_rule import PySubprocess