Running other people's programs is insecure.
Rogue dependencies*
🎯 or hacked library code
🏴☠️ (et cet.
~/.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! 😬
Run scary software in separate secure containers:
podman run -it -v .:/src -e PATH=/src debian:stable-slim scary-binary
or you can simply
sandbox-run scary-binary
which uses bubblewrap** (of
Flatpak fame) under the hood.
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 /
Whenever you want to run a scary executable, simply run:
sandbox-run scary-app args
to run scary-app
in a secure sandbox.
You can also pass additional bubblewrap arguments to individual
process invocations via $BWRAP_ARGS
environment variable. E.g.:
BWRAP_ARGS='--bind /opt /opt' \
python -c 'import os; print(os.listdir("/opt"))'
For 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.
The current working directory is mounted with read-write permissions**, while everything else 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.
See bwrap
switches --seccomp FD
and --add-seccomp-fd FD
.
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.
BWRAP_ARGS=
– Extra arguments passed tobwrap
process; space or line-delimited (if arguments such as paths themselves contain spaces).VERBOSE=
– Print fullexec bwrap
command line right before execution.
To see what's failing, run the sandbox with something like strace -f -e '%file,%process' ...
.
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 80
To 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 tkinter
See more examples on the ArchWiki.
You see a mistake—you fix it. Thanks!
See a few alternatives discussed over at
sandbox-venv
.