Shell Escape for Python
The `shellescape` Python module provides the `shellescape.quote()` function, which is a backport of Python 3.8's `shlex.quote()` functionality. It safely escapes strings for use as single tokens within shell commands, mitigating shell injection vulnerabilities when executing external commands from Python scripts. The library is currently active, with its latest release `v3.8.1` in January 2020.
Warnings
- gotcha Prefer `shlex.quote` directly on Python 3.3+ (especially 3.8+). The `shellescape` library is a backport designed for older Python versions (Python 2.x and 3.x < 3.3). Using it on modern Python where `shlex.quote` is natively available is redundant and may introduce subtle behavioral differences if the backport diverges from the latest CPython implementation.
- gotcha Understand that `shellescape.quote()` escapes *individual* tokens. It does not magically make an entire command string safe if other parts are unescaped or if `shell=True` is used improperly with complex commands. The safest approach is to use `subprocess.run()` with a list of arguments (i.e., `shell=False`, which is the default) to avoid shell interpretation entirely.
- breaking Version `3.8.1` included a bugfix (`#2`) that changed the definition of the quote regex to align with CPython v3.8.1 and removed `re.ASCII` for Python 2 support. While this was a bugfix to improve correctness, it means the escaping behavior might differ subtly from previous `shellescape` versions if code relied on the prior (buggy) definition.
Install
-
pip install shellescape
Imports
- quote
from shellescape import quote
Quickstart
from shellescape import quote
import subprocess
user_input = "my file with spaces; evil command"
safe_argument = quote(user_input)
# Best practice: pass arguments as a list to subprocess.run for security (shell=False is default)
# However, shellescape is used when you absolutely need to construct a shell string
# For demonstration, we'll show how to use the escaped string in a shell command string:
command = f"echo {safe_argument}"
print(f"Original input: '{user_input}'")
print(f"Escaped argument: '{safe_argument}'")
print(f"Constructed command: '{command}'")
# Example of safe execution (though direct list is preferred when possible)
# DO NOT use shell=True with unescaped user input.
# If shell=True is necessary, ensure all user-provided tokens are escaped.
# For this example, we demonstrate the output of the escaped string:
# subprocess.run(command, shell=True, check=True)