{"id":4392,"library":"shellescape","title":"Shell Escape for Python","description":"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.","status":"active","version":"3.8.1","language":"en","source_language":"en","source_url":"https://github.com/chrissimpkins/shellescape","tags":["shell","security","backport","shlex"],"install":[{"cmd":"pip install shellescape","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"The primary function is `quote`, directly imported from the `shellescape` package. There is no `shlex` submodule within `shellescape`.","wrong":"import shellescape; shellescape.shlex.quote()","symbol":"quote","correct":"from shellescape import quote"}],"quickstart":{"code":"from shellescape import quote\nimport subprocess\n\nuser_input = \"my file with spaces; evil command\"\nsafe_argument = quote(user_input)\n\n# Best practice: pass arguments as a list to subprocess.run for security (shell=False is default)\n# However, shellescape is used when you absolutely need to construct a shell string\n# For demonstration, we'll show how to use the escaped string in a shell command string:\ncommand = f\"echo {safe_argument}\"\n\nprint(f\"Original input: '{user_input}'\")\nprint(f\"Escaped argument: '{safe_argument}'\")\nprint(f\"Constructed command: '{command}'\")\n\n# Example of safe execution (though direct list is preferred when possible)\n# DO NOT use shell=True with unescaped user input.\n# If shell=True is necessary, ensure all user-provided tokens are escaped.\n# For this example, we demonstrate the output of the escaped string:\n# subprocess.run(command, shell=True, check=True)","lang":"python","description":"This quickstart demonstrates how to import the `quote` function and use it to escape user-provided input. The escaped string can then be safely embedded as a single token in a shell command string. While `shellescape` facilitates constructing shell command strings, the general best practice for executing external commands in Python is to pass arguments as a list to `subprocess.run()` (which defaults to `shell=False`) to avoid shell interpretation entirely."},"warnings":[{"fix":"On Python 3.3 and newer, use `from shlex import quote` directly. Only use `shellescape` if targeting environments where `shlex.quote` is not present.","message":"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.","severity":"gotcha","affected_versions":"< 3.3 (when `shlex.quote` is unavailable)"},{"fix":"Always pass arguments as a list to `subprocess.run()` (e.g., `subprocess.run(['command', arg1, arg2])`). If `shell=True` is strictly required, ensure *every* user-controlled component in the command string is individually escaped using `shellescape.quote()` or `shlex.quote()`.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Review any code that relies on `shellescape.quote()`'s exact output, especially when upgrading from versions prior to `3.8.1`, and test against the new behavior.","message":"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.","severity":"breaking","affected_versions":"< 3.8.1"}],"env_vars":null,"last_verified":"2026-04-12T00:00:00.000Z","next_check":"2026-07-11T00:00:00.000Z"}