sandbox-run: run command in a secure OS sandbox
Problem statement
Running other people's programs is inherently insecure. Rogue dependencies* 🎯 or hacked library code 🏴☠️ (et cet. ⚠️) can wreak havoc, including access all your private parts ‼️—think all current user's credentials and more personal bits like:
~/.ssh,~/.pki/nssdb/,~/.mozilla/firefox/<profile>/key4.db,~/.mozilla/firefox/<profile>/formhistory.sqlite...
✱ Running any Electron app relies on impeccability of hundreds or thousands of dependencies, NodeJS and Chromium to say the least! 😬
Solution
Run scary software in separate secure containers:
podman run --rm -it -v "$PWD:$PWD" --net=host --workdir="$PWD" debian:stable-slim ./scary-binary
or you can simply
sandbox-run scary-binary
(e.g. sandbox-run npx @google/gemini-cli)
which uses bubblewrap (of
Flatpak fame) to spawn your native OS container under the hood,
and, after downloading almost 500 MB ❗ of JavaScript sources,
executes this untrusted third-party's Node/NPM package anonymously and securely,
with its CWD in $PWD and new $HOME in $PWD/.sandbox-home.
Installation
There are no dependencies other than a POSIX shell with
its standard set of utilities
and bubblewrap.
The installation process, as well as the script runtime,
should behave similarly on all relevant compute platforms,
including GNU/Linux and even
Windos/WSL. 🤞
# Install the few, unlikely to be missing dependencies, e.g. sudo apt install coreutils binutils bubblewrap # Download the script and put it somewhere on PATH curl -vL 'https://bit.ly/sandbox-run' | sudo tee /usr/local/bin/sandbox-run sudo chmod +x /usr/local/bin/sandbox-run # Mark executable sandbox-run # Usage: sandbox-run ARG... sandbox-run ls /
Usage
Whenever you want to run a scary executable, simply run:
sandbox-run scary-app args
to run scary-app in a secure sandbox.
Extra Bubblewrap arguments
You can also pass additional bubblewrap arguments to individual
process invocations via $BWRAP_ARGS environment variable. E.g.:
BWRAP_ARGS='--bind /opt /opt' \
sandbox-run ./NVIDIA-Driver-Installer.runFor details, see bubblewrap --help or man 1 bwrap.
Note, .env file
at project root is respected, and sourced for the sandbox environment.
See more specific examples below.
Filesystem mounts
The current working directory is mounted with read-write permissions, while everything else required for a successful run (e.g. /usr) is mounted read-only. In addition:
"$PWD/.sandbox-home"is bind-mounted as"$HOME",
To mount extra endpoints, use BWRAP_ARGS= with switches --bind or --bind-ro.
Anything else not explicitly mounted by an extra CLI switch
is lost upon container termination.
Linux Seccomp
See bwrap switches --seccomp FD and --add-seccomp-fd FD.
Runtime monitoring
If environment variable VERBOSE= is set to a non-empty value,
the full bwrap command line is emitted to stderr before execution.
You can list bubblewraped processes using the
command lsns
or the following shell function:
list_bwrap () { lsns -u -W | { IFS= read header; echo "$header"; grep bwrap; }; } list_bwrap # Function call
You can run sandbox-run bash to spawn interactive shell inside the sandbox.
Environment variables
BWRAP_ARGS=– Extra arguments passed tobwrapprocess; space or line-delimited (if arguments such as paths themselves contain spaces).SANDBOX_RO_BIND=– List of additional path glob expressions to mount read-only inside the sandbox.VERBOSE=– Print fullexec bwrapcommand line right before execution.
Debugging
To see what's failing, run the sandbox with something like colorstrace -f -e '%file,%process' ....
Examples
To pass extra environment variables, other than those filtered by default,
use bwrap --setenv, e.g.:
BWRAP_ARGS='--setenv OPENAI_API_KEY c4f3b4b3' sandbox-run my-ai-prog # or pass via .env (dotenv) file
To run the sandboxed process as superuser (while still retaining all the security functionality of the container sandbox), e.g. to open privileged ports, use args:
BWRAP_ARGS='--uid 0 --cap-add cap_net_bind_service' sandbox-run python -m http.server 80To run GUI (X11) apps, some prior success was achieved using e.g.:
BWRAP_ARGS='--bind /tmp/.X11-unix/X0 /tmp/.X11-unix/X8 --setenv DISPLAY :8' \
sandbox-run python -m tkinterSee more examples on the ArchWiki.
Contributing
You see a mistake—you fix it. Thanks!
Alternatives
See a few alternatives discussed over at sister project
sandbox-venv.