Updated in 2026 with Python 3 examples and current links.
Certain Python functions are dangerous if used carelessly. Python’s documentation typically flags the risks but rarely illustrates them well.
This post covers a few categories of dangerous functions and safer alternatives. If you spot these in the wild, pay close attention.
*Illustration by Carissa Sandoval*
The Command Injection Series
The first group of dangerous Python functions revolve around trusting user-provided input and piping it into a shell.
Why they’re useful
Sometimes you need to call a command-line application, and Python’s
subprocess.call() with
shell=True makes that convenient.
os.system() and
os.popen() have been
deprecated in favor of the subprocess module. They have
a simple API and they’ve been around for a while so you may run into them in
older applications.
Why they’re dangerous
shell=True (and the similar tools in os) lets someone craft input that
issues different commands than the ones you intended.
A dangerous example
Let’s say we want to write a function to transcode a user-specified video file into a different format. We ask the user where to find the file on disk and then run it through ffmpeg to transcode it. What could go wrong?
import subprocess
def transcode_file():
filename = input('Please provide the path for the file to transcode: ')
command = 'ffmpeg -i "{source}" output_file.mpg'.format(source=filename)
subprocess.call(command, shell=True) # a bad idea!
What if someone provides a file with a name like "; rm -rf /? If the host
machine runs the Python process as a privileged user, that could delete all
of the files on the machine. That’s bad.
What to use instead
subprocess with shell=False. It protects you against most of the risk
associated with piping commands to the shell. If you go this route,
shlex.split()
makes it easier to prepare the command (and is what the Python docs recommend).
sh - Useful for issuing commands to other
applications. I had some trouble issuing complex commands through sh before
because of the way it quotes variables. That said, if it works for your use
case, then go for it!
If you must use them…
Escape your variables! Use
shlex.quote()
to properly escape shell arguments.
Additional references
- Subprocess documentation on security implications
- OWASP Command Injection
- Shellshock affects os.popen
- PEP 324 - Subprocess
Code Injection - exec, eval
The second group of dangerous functions relate to taking input and interpreting it as Python code.
Why they’re useful
exec() and
eval() take strings
and turn them into executable code. They can be useful, especially if you are
the one who controls the input. As one example, I’ve used eval before
to evaluate a large dict-like string into a dictionary.
Why they’re dangerous
eval() and exec() will execute whatever we feed them. A malicious string
can erase your data, expose your secret keys, or dump your database.
A dangerous example
Related to the previous example, suppose you’re evaling a string that looks
like this: "os.system('rm -rf /') # dangerous!". It, too, could erase all
your files.
What to use instead
It depends on what you’re doing. eval and exec serve many purposes,
so there’s no single replacement.
If you’re evaluating a string that contains a Python literal (a dict, list,
string, number, etc.), use
ast.literal_eval().
It parses the expression without executing arbitrary code.
If you’re using them to perform serialization / deserialization, it would
probably be better to use another format, such as JSON, which can be loaded
with the json module.
If you must use them…
Again, escape your input. You can also disable the built-ins to make it harder to craft malicious input, which Ned Batchelder covers in Eval really is dangerous.
Additional references
Next time…
We’ve covered ways in which user input can pose serious risks to Python applications. In the next part of this series, we’ll discuss issues related to deserializing data, loading yaml configurations, information leakage, and more.
Thanks to Zach Schipono and Carissa Sandoval for reviewing drafts of this.