AUTHOR
Julien Delange, Founder and CEO
Julien is the CEO of Codiga. Before starting Codiga, Julien was a software engineer at Twitter and Amazon Web Services.
Julien has a PhD in computer science from Universite Pierre et Marie Curie in Paris, France.
What is the subprocess module in Python?
The subprocess
module in Python creates
new OS processes (think of it like a fork
on steroids). The module has different methods (e.g., Popen
, run
)
to execute new processes, get their outputs and check that they execute without any issues.
This module is often used for system administration/devops scripts, where a program needs to interact with
other commands. It's convenient for automating tasks and more often more powerful than
shell scripts (and Python more a more expressive language). For these reasons, the subprocess
module is really popular.
Why the subprocess module may be unsafe?
The subprocess
module has multiple convenient features that introduce potential vulnerability.
When the argument shell
is set to True
in its functions (such as Popen
or run
), the new
process is executed through the shell.
When shell=True
is used, the command must be formatted as if it were used in a shell. And it
also means that if the command contains any user inputs, the user may inject commands to execute
and compromise the system.
Say you have the following code:
import subprocess
...
subprocess.run(f"mycommand {user} {argument}", shell=True, check=True)
If a user somewhat managed to pass the value ; rm -rf / ;
in the user
or argument
variable,
this command would remove all files that belong to the user executing the command. And if
the program is executed as root, it could remove all files on the system.
Such vulnerability is known as CWE-78:
Improper Neutralization of Special Elements used in an OS Command. For this reason, it's really
important to make sure that any method of the subprocess
module is safely used.
How to safely and securely use the subprocess Python module?
The best fix is to avoid using shell=True
altogether. It may be difficult to do so, especially
when chaining multiple commands or when the invoked program needs the shell environment.
One remediation is to use the shlex
module and its split
method.
The split
method splits all the arguments, making sure they are quoted.
By using the shlex.split
method, the fix would then be the code above would be changed to:
import subprocess
import shlex
...
subprocess.run(shlex.split(f"mycommand {user} {argument}"), shell=True, check=True)
Still, the solution with shlex
is one remediation and may not work everywhere (and raising
portability issues). The best solution to use safely subprocess
is to avoid using
shell=True
.
Automatically detect unsafe use of the subprocess module
The Codiga IDE plugins and the integrations with GitHub, GitLab, or Bitbucket let you detect unsafe usage of the Python subprocess
module.
The Codiga static code analysis not only detects unsafe code but also suggests fixes to correct it. There is a dedicated rule to detect unsafe usage of the subprocess
module.
To use this rule consistently, all you need to do is to install the integration in your IDE (for VS Code or JetBrains) or code management system and add a codiga.yml
file at the root of your profile with the following content:
rulesets:
- python-security
It will then check all your Python code against 100+ rules that detect unsafe and insecure code and suggests fixes for each of them.