python.lang.security.audit.dangerous-subprocess-use-audit.dangerous-subprocess-use-audit
semgrep
Author
unknown
Download Count*
License
Detected subprocess function '$FUNC' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.
Run Locally
Run in CI
Defintion
rules:
- id: dangerous-subprocess-use-audit
pattern-either:
- patterns:
- pattern-not: subprocess.$FUNC("...", ...)
- pattern-not: subprocess.$FUNC(["...",...], ...)
- pattern-not: subprocess.$FUNC(("...",...), ...)
- pattern-not:
patterns:
- pattern-not-inside: |
$ARR = ["=~/(sh|bash|ksh|csh|tcsh|zsh)/", "-c", ...]
...
- pattern-inside: |
$ARR = [...]
...
- pattern-either:
- pattern: subprocess.$FUNC(*$ARR, ...)
- pattern: subprocess.$FUNC([*$ARR, ...])
- pattern-not: subprocess.CalledProcessError(...)
- pattern-not: subprocess.SubprocessError(...)
- pattern: subprocess.$FUNC(...)
- patterns:
- pattern: subprocess.$FUNC("=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c",...)
- pattern-not: subprocess.$FUNC("=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c","...",...)
- patterns:
- pattern-either:
- pattern: subprocess.$FUNC(["=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c",...],...)
- pattern: subprocess.$FUNC(("=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c",...),...)
- pattern-not: subprocess.$FUNC(["=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c","...",...],...)
- pattern-not: subprocess.$FUNC(("=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c","...",...),...)
- patterns:
- pattern: subprocess.$FUNC("=~/(python)/",...)
- pattern-not: subprocess.$FUNC("=~/(python)/","...",...)
- patterns:
- pattern-either:
- pattern: subprocess.$FUNC(["=~/(python)/",...],...)
- pattern: subprocess.$FUNC(("=~/(python)/",...),...)
- pattern-not: subprocess.$FUNC(["=~/(python)/","...",...],...)
- pattern-not: subprocess.$FUNC(("=~/(python)/","...",...),...)
message: Detected subprocess function '$FUNC' without a static string. If this
data can be controlled by a malicious actor, it may be an instance of
command injection. Audit the use of this call to ensure it is not
controllable by an external resource. You may consider using
'shlex.escape()'.
metadata:
owasp:
- A01:2017 - Injection
- A03:2021 - Injection
cwe:
- "CWE-78: Improper Neutralization of Special Elements used in an OS
Command ('OS Command Injection')"
asvs:
section: "V5: Validation, Sanitization and Encoding Verification Requirements"
control_id: 5.3.8 OS Command Injection
control_url: https://github.com/OWASP/ASVS/blob/master/4.0/en/0x13-V5-Validation-Sanitization-Encoding.md#v53-output-encoding-and-injection-prevention-requirements
version: "4"
references:
- https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess
- https://docs.python.org/3/library/subprocess.html
- https://docs.python.org/3/library/shlex.html
- https://semgrep.dev/docs/cheat-sheets/python-command-injection/
category: security
technology:
- python
confidence: LOW
cwe2022-top25: true
cwe2021-top25: true
subcategory:
- audit
likelihood: LOW
impact: HIGH
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
vulnerability_class:
- Command Injection
languages:
- python
severity: ERROR
Examples
dangerous-subprocess-use-audit.py
# cf. https://github.com/returntocorp/semgrep/blob/develop/docs/writing_rules/examples.md#auditing-dangerous-function-use
import subprocess
import sys
# ok:dangerous-subprocess-use-audit
subprocess.call("echo 'hello'")
# ok:dangerous-subprocess-use-audit
subprocess.call(["echo", "a", ";", "rm", "-rf", "/"])
# ok:dangerous-subprocess-use-audit
subprocess.call(("echo", "a", ";", "rm", "-rf", "/"))
# ok:dangerous-subprocess-use-audit
raise subprocess.CalledProcessError("{}".format("foo"))
# ok:dangerous-subprocess-use-audit
raise subprocess.SubprocessError("{}".format("foo"))
# ruleid:dangerous-subprocess-use-audit
subprocess.call("grep -R {} .".format(sys.argv[1]))
def foobar(user_input):
cmd = user_input.split()
# ruleid:dangerous-subprocess-use-audit
subprocess.call([cmd[0], cmd[1], "some", "args"])
# ruleid:dangerous-subprocess-use-audit
subprocess.call("grep -R {} .".format(sys.argv[1]), shell=True)
# ruleid:dangerous-subprocess-use-audit
subprocess.call("grep -R {} .".format(sys.argv[1]), shell=True, cwd="/home/user")
# ruleid:dangerous-subprocess-use-audit
subprocess.run("grep -R {} .".format(sys.argv[1]), shell=True)
# ruleid:dangerous-subprocess-use-audit
subprocess.run(["bash", "-c", sys.argv[1]], shell=True)
# ok:dangerous-subprocess-use-audit
subprocess.call(["echo", "a", ";", "rm", "-rf", "/"])
cmd_cmd = ["sh", "-c"]
# ruleid:dangerous-subprocess-use-audit
subprocess.call([*cmd_cmd, "rm", "-rf", "/"])
echo_cmd = ["echo", "a", ";"]
# ok:dangerous-subprocess-use-audit
subprocess.call([*echo_cmd, "rm", "-rf", "/"])
def vuln_payload(payload: str) -> None:
with tempfile.TemporaryDirectory() as directory:
python_file = Path(directory) / "hello_world.py"
python_file.write_text(textwrap.dedent("""
print("What is your name?")
name = input()
print("Hello " + name)
"""))
# ruleid:dangerous-subprocess-use-audit
program = subprocess.Popen(['python2', str(python_file)], stdin=subprocess.PIPE, text=True)
program.communicate(input=payload, timeout=1)
Short Link: https://sg.run/zL8G