shandbox

History↓

shandbox is a simple Linux sandboxing script that serves my needs well. Perhaps it works for you too? No dependencies between a shell and util-linux (unshare and nsenter).

In short, it aims to provide fairly good isolation for personal files (i.e. your $HOME) while being very convenient for day to day use. It's designed to be run as an unprivileged user - as long as you can make new namespaces you should be good to go. By default /home/youruser/sandbox shows up as /home/sandbox within the sandbox, and other than standard paths like /usr, /etc, /tmp, and so on it's left for you to either copy things into the sandbox or expose them via a mount. There's a single shared sandbox (i.e. processes within the sandbox can see and interact with each other, and the exposed sandbox filesystem is shared as well), which trades off some ease of use for the security you might get with a larger number of more targeted sandboxes. On the other hand, you only gain security from a sandbox if you actually use it and this is a setup that offers very low friction for me. The network is not namespaced (although this is something you could change with a simple edit).

Usability is both subjective and highly dependent on your actual use case, so the tradeoffs may or may not align with what is interesting for you! Bubblewrap is an example of a mature alternative unprivileged sandboxing tool that offers a lot of configurability as well as options with greater degrees of sandboxing. Beyond that, look to Firecracker based solutions or gvisor. shandbox obviously aims to provide a reasonable sandbox as much as Linux namespaces alone are able to offer, but if you're looking for a security property stronger than "makes it harder for something to edit or access unwanted files" it's down to you to both carefully review its implementation and consider alternatives.

Usage example

$ shandbox run uvx pycowsay
Installed 1 package in 5ms

  ------------
< Hello, world >
  ------------
   \   ^__^
    \  (oo)\_______
       (__)\       )\/\
           ||----w |
           ||     ||
$ shandbox status
running (pid 1589364)

log:
  2026-02-11 13:02:51 stopped
  2026-02-11 13:05:06 started (pid 1589289)
$ shandbox add-mount ~/repos/llvm-project /home/sandbox/llvm-project
mounted /home/asb/repos/llvm-project -> /home/sandbox/llvm-project
$ shandbox run touch /home/sandbox/llvm-project/write-attempt
touch: cannot touch '/home/sandbox/llvm-project/write-attempt': Read-only file system
$ shandbox remove-mount /home/sandbox/llvm-project
unmounted /home/sandbox/llvm-project
$ shandbox add-mount --read-write ~/repos/llvm-project /home/sandbox/llvm-project
mounted /home/asb/repos/llvm-project -> /home/sandbox/llvm-project
$ shandbox run touch /home/sandbox/llvm-project/write-attempt

shandbox enter will open a shell within the sandbox for easy interactive usage. As a convenience, if the current working directory is in $HOME/sandbox (e.g. $HOME/sandbox/foo) then the working directory within the sandbox for shandbox run or shandbox enter will be set to the appropriate path within the sandbox (/home/sandbox/foo in this case). i.e., the case where this mapping is trivial. Environment variables are not passed through.

Functionality overview

Implementation approach

The core sandboxing functionality is provided by the Linux namespaces functionality exposed by unshare and nsenter. The script's implementation should be quite readable but I'll try to summarise some key points here.

The goal is that:

To implement that:

Making it your own

The script should be straight-forward enough to customise to your needs if they're not too dissimilar to what is offered out of the box. Some variables at the top provide things you may be more likely to want to change, such as the home directory location, and a list of files or directories in $HOME to always bind-mount into the sandbox home:

SANDBOX_HOME_DIR="$HOME/sandbox"
HOME_FILES_TO_MAP=".bashrc .vimrc"
HOME_DIRS_TO_MAP=".vim bin"
SB_HOME="/home/sandbox"
SB_PATH="$SB_HOME/bin:/usr/local/bin:/usr/bin"

Article changelog