shellsafe
Run shell commands safely using Python 3.14 template strings. Values can never turn into commands.
from shellsafe import run
message = get_user_input() # "fix; rm -rf ~"
run(t"git commit -m {message}")
# argv: ["git", "commit", "-m", "fix; rm -rf ~"]
# one command; the scary text is just an argument
Why this package exists
Python 3.14 added template strings (PEP 750). Now Python keeps your fixed text and your values separate at the language level.
Shell commands are the first place people want to use this. That is because f-strings inside shell commands have caused real security bugs for ten years:
subprocess.run(f"git commit -m {message}", shell=True)
# if message = "fix; rm -rf ~" -> two commands run. The second one is bad.
Python planned to solve this officially (PEP 787), but that PEP is still deferred. It is not in the Python 3.15 release candidates. So today there is no standard way to run shell commands safely with templates. This package fills that gap.
Install
pip install shellsafe
Needs Python 3.14 or newer.
How to use
Run a command. Your values always stay one argument each. run() never invokes
a shell, so injection is impossible on any platform:
from shellsafe import run
run(t"mkdir {path}")
run(t"docker build -t {tag} .", check=True, timeout=300)
Get the output as text:
from shellsafe import capture
res = capture(t"grep {pattern} {file}")
print(res.stdout, res.returncode)
Need pipes? Works on Linux and macOS. Your values are quoted safely first:
from shellsafe import shx
shx(t"cat {file} | wc -l")
Want to see exactly what will run?
from shellsafe import plan
print(plan(t"git commit -m {message}"))
# argv: ["git","commit","-m","fix; rm -rf ~"]
Safety rules
| Case | What happens |
|---|---|
| Any value you pass | becomes one argument, exactly as given |
| Value used as the program name | error: program names must be written as fixed text |
| Shell features on Windows | error: we cannot make Windows safe this way, so we say no |
| RAW() misuse | error: one value only, used as-is, no nesting |
RAW(...) marks content you have already made safe by hand. It is loud and easy
to find in code review, so trust is never hidden.
Find old dangerous patterns
Already have code using f-strings in shell commands? The scanner finds them:
shellsafe audit src/
It detects f-strings passed to os.system, subprocess.run(shell=True), and
other shell executors. Get machine-readable output:
shellsafe audit src/ --json
Filter by severity:
shellsafe audit src/ --severity warning
Suppress known-safe findings inline:
# shellsafe: ignore AU001 reason: tested, value is constant
os.system(f"echo {safe_value}")
Suppress from the command line:
shellsafe audit src/ --ignore AU004
Limits
- Shell features (pipes, redirections) work on Linux and macOS only. Windows supports plain commands only.
run()refuses templates that contain shell metacharacters. Useshx()for those.- Byte values are rejected. Decode them first.
- We keep your command safe to build and run. Testing what your command does is still your job.
Needs
- Python 3.14 or newer
- Linux, macOS, Windows (pipes work on Linux and macOS only)
More
- Source and issues: github.com/rahulXs/shellsafe
- Blog: rahulxs.github.io/shellsafe
- Want to help? See CONTRIBUTING.md in the repository.
License: MIT
Metadata
Release files for shellsafe 0.3.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| shellsafe-0.3.5.tar.gz | 24.9 kB | With provenance | Details for shellsafe-0.3.5.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| shellsafe-0.3.5-py3-none-any.whl | Python 3 | none | any | Details for shellsafe-0.3.5-py3-none-any.whl |
Total release size: 42.2 kB
Release files / shellsafe-0.3.5.tar.gz
| Download URL | shellsafe-0.3.5.tar.gz |
|---|---|
| Size | 24.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d42c544c07f5068e166284230499119f9fdb3f5159cca7927a673b2a1387992b
|
|
BLAKE2b-256 checksum How to use checksums |
d2521f9fdf42571a2f79686526dd1a4bb6fab3513d87b77a8acb73adf41e5c69
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / shellsafe-0.3.5-py3-none-any.whl
| Download URL | shellsafe-0.3.5-py3-none-any.whl |
|---|---|
| Size | 17.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
adaf6a0f8f8a4ee2ad4eb18dbdc320476b39ac8691354749e5b7d8bd7d1ce162
|
|
BLAKE2b-256 checksum How to use checksums |
7ca31dd7a62c5837c0251a30235d625786a51f8dae6ddaaf0f91b1ff7378c7da
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logSecurity for shellsafe 0.3.5
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for shellsafe-0.3.5.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.