gotchapythonCritical
subprocess.run with shell=True is a security risk
Viewed 0 times
shell injectionsubprocess securityshell=Truecommand injectionshlex
Error Messages
Problem
Using subprocess.run(cmd, shell=True) with user input enables shell injection attacks. An attacker can append commands with ; or && to execute arbitrary code on the system.
Solution
Never use shell=True with user input. Pass arguments as a list:
# BAD — shell injection risk
subprocess.run(f'grep {user_input} file.txt', shell=True)
# GOOD — arguments are escaped automatically
subprocess.run(['grep', user_input, 'file.txt'])
# If you need shell features (pipes, globbing):
import shlex
subprocess.run(shlex.split(f'grep {shlex.quote(user_input)} file.txt'), shell=False)
# For pipes without shell=True:
from subprocess import Popen, PIPE
p1 = Popen(['cat', 'file.txt'], stdout=PIPE)
p2 = Popen(['grep', 'pattern'], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]
# BAD — shell injection risk
subprocess.run(f'grep {user_input} file.txt', shell=True)
# GOOD — arguments are escaped automatically
subprocess.run(['grep', user_input, 'file.txt'])
# If you need shell features (pipes, globbing):
import shlex
subprocess.run(shlex.split(f'grep {shlex.quote(user_input)} file.txt'), shell=False)
# For pipes without shell=True:
from subprocess import Popen, PIPE
p1 = Popen(['cat', 'file.txt'], stdout=PIPE)
p2 = Popen(['grep', 'pattern'], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]
Why
shell=True passes the command string to /bin/sh, which interprets shell metacharacters. Input like 'file.txt; rm -rf /' would execute both commands. Without shell=True, arguments are passed directly to the executable without shell interpretation.
Gotchas
- shlex.quote() escapes shell metacharacters if you must use shell=True
- On Windows, shell=True uses cmd.exe which has different escaping rules
- subprocess.run without shell=True requires the command as a list, not a string
Code Snippets
Safe subprocess usage
import subprocess, shlex
user_input = 'pattern'
# SAFE: list arguments
subprocess.run(['grep', '-r', user_input, '.'])
# SAFE: shlex.quote for shell=True
subprocess.run(f'grep -r {shlex.quote(user_input)} .', shell=True)Context
When executing system commands with any user-provided input
Revisions (0)
No revisions yet.