SkillAgentSearch skills...

Treesandbox

Another Linux sandbox tool. Rootless. Allows unlimited nesting if you want. Single-file .py . No 3rd-party python lib needed.

Install / Use

/learn @garywill/Treesandbox

README

English | 中文

Tree Sandbox for Linux

You’ve played with Podman, Firejail, Flatpak, Bubblewrap, ...

Tree Sandbox is another rootless Linux sandbox tool.

"Tree-shaped" sandbox: multi-layer nesting and branching, like a “tree” composed of multiple sub-containers.

Comparison with other sandbox tools

Compare with Firejail / Flatpak

| Feature | Tree sandbox | Firejail | Flatpak | | --- | --- | --- | --- | | Filesystem: privacy vs size vs convinience | ◐ Pick needed paths from host fs. Score 2/3 | ✘ Use host fs, masking unneeded paths. Score 1/3 | ◐ Download container image. Score 2/3 | | Single-instance for same-app sandbox (cmd/args sent to first-started instance) | ● | ● | ● | | Multi-instance for same-app sandbox (each other isolated & independent) | ● | ● | ✘ | | Containers nesting | ● "Containers tree" is the way it works. We run "untrusted" and "semi-trusted" procs in different layers of a sandbox | ✘ Refuses to be nested | ✘ | | No install/build. No system daemon | ● Single-file .py. No host root needed | ✘ Need install and suid | ✘ Need system daemon | | Works out of the box (for specific app) | ◐ Users need edit some configs first | ● Has some built-in app profiles | ● Flathub | | No traces in host HOME dir | ● | ● | ✘ | | Able to open in host when in-sandbox calls xdg-open | ● Can replace xdg-open by asking script. User can copy url/path/args | ✘ | ● Managed by portal | | Dynamically change accessable file/hardware list | ✘ Pre-configured mount list | ✘ Pre-configured mount list | ● Portal can do dynamically change, but in-sandbox see unpredictable file path | | unshare net ns with host. Sandbox has Internet. Choosily "merge" host's and sandbox's allowed localhost ports | ● tun/tap + nftables (rootless). Fine-grained control | ◐ | ◐ |

Compare with Bubblewrap

| Feature | Tree sandbox | Bubblewrap | | --- | --- | --- | | How sandbox is configured | Edit config file | By CLI args | | Works out of the box (for a basic-system sandbox) | ● | ✘ Need long args to make basic system | | Integration of common tools (eg isolated X11 server, DBUS filter proxy etc.), and common socket path mounting options | ● | ✘ | | Single-instance for same-app sandbox (cmd/args sent to first-started instance) | ● | ✘ | | Multi-instance for same-app sandbox (each other isolated & independent) | ● | ● | | Host can get in-sandbox shell easily, via a socket | ● Currently usable under some config case. Will fully support | ✘ Need host root to nsenter |

Features and status

  • [x] No root needed; no system daemon; no host caps or suid ; no subuid/subgid needed.

  • [x] Image-free containers. Tools like vim/git don’t need to be reinstalled inside.

  • GUI in sandbox

    • [x] Optionally expose host X11 to the sandbox.
    • [x] Optional isolated X11 using Weston + Xwayland (GPU usable) ( with icewm).
    • [x] Optional isolated X11 using Xephyr ( with icewm).
    • [x] Optional seamless isolated X11 proxy via Xpra.
    • [ ] Optional expose Wayland to the sandbox.
    • [ ] Optional isolated full desktop running inside a single window.
    • [x] Optional clipboard sync (from sandbox to host; the reverse direction can temporarily be done by IME paste).
  • [x] Expose an in-container shell interface to the host, allowing the host to easily get (partially usable. Full support in plan).

  • Optionally expose real hardware devices to the sandbox

    • [x] Expose GPU devices to the sandbox.
    • [x] Expose all hardware devices to the sandbox.
  • DBus

    • [x] Optional host DBus exposure to the sandbox.
    • [x] Optional DBus communication filtering.
  • Sandbox network

    • [x] Optional don't manage network (don't unshare net ns)
    • [x] Optional network control
      • [x] Controllable tun/tap (managed by pasta) network interface
      • [x] Custom nftables rules (rootless) in sandbox.
  • [x] Mount AppImage and squashfs internally to access their contents inside the sandbox.

  • [x] Optionally expose the PulseAudio interface to the sandbox.

  • [x] Optionally expose the CUPS interface to the sandbox.

  • For the same-name sandbox: single-app/multi-app; single-instance/multi-instance (app selection at startup, instance management, and cmd/args passing)

    Note: the user-configured sandbox_name is used to identify a “same-name sandbox”.

    • [x] One sandbox can configure multiple apps; you can choose the app at startup (e.g., put multiple apps from the <ins><u> same vendor </u></ins> into one sandbox for their easier interaction).
    • [x] Multi-instance mode: starting the sandbox multiple times creates multiple isolated independent instances.
    • [x] Single-instance mode: after starting one sandbox, starting the same sandbox again passes command arguments to the <ins><u>already-running</u></ins> sandbox.
  • [x] “Containers tree” internally can do:

    • [x] Per-layer control of whether a type of ns is unshared or not from parent layer.
    • [x] Per-layer environment variable control.
    • [x] Per-layer fine-grained new-rootfs filesystem setup list:
      • [x] bind mounts (rw/ro) for dir/file/socket/chardevice; symlink ; tmpfs . etc.
      • [ ] overlayfs
  • [x] Handle uid_map and user ns ; Drop caps; noNewPrivs ; procfs hidepid=1

  • [x] Watchdog.

  • [ ] Separate PGID/SID, then implement some signal forwarding.

  • [ ] Pass user-specified fd to the app.

  • [ ] Quickly list instances and procs from host

What is “containers tree”

Tree Sandbox is designed so that a sandbox is composed of multiple layered sub-containers connected as a “containers tree”. The “tree” has branches and container nodes. The “connection” between nodes can be any combination of namespaces being “unshared” or “not unshared” .

With this design, “untrusted” procs and “semi-trusted” procs run in different layers of a sandbox; User's app and other companion procs run in different layers.

Here is an example of what a sandbox container tree might look like:

[Linux Host]
    Host X11
    Host DBus services

    [TreeSandbox Sandbox]
     |
     |--[Sub-container: Untrusted zone]
     |   |
     |   |--[Sub-container: User App: Untrusted]
     |   |      The user's app runs here
     |   |
     |   |--[Sub-container: Companion procs (Group 2): Untrusted]
     |          Internal X11 services
     |          Internal DBus services
     |
     |--[Sub-container: Companion procs (Group 1): Semi-trusted]
            Proc that forward between internal and host X11
            DBus proxy and filtering proc

With the “containers tree” model, we can isolate procs of different "classes" inside the sandbox <ins><u> without requiring host subuid/subgid </u></ins>.

The way it works allow finely controlling the isolation degree and filesystem visibility for each layer. If you want, you can even play with unlimited nesting.

To Use

Quick Trying

git clone --shallow-since=2026-03-01 https://github.com/garywill/treesandbox
cd treesandbox
python3 -IBS ./treesandbox.py

(-IBS means we don't need third-party python library)

If you see in-sandbox shell prompt, congratulations! It works!

Now you can take a look at dependency list, and consider installing some optional software to unlock more integrated features.

Get Your Sandbox(es) Ready

Above just checked your computer can run Tree Sandbox. Before actual use, you want to make your startup script(s) of your specific sandbox(es) ready.

Currently, need to manually do:

  1. Copy treesandbox.py in this repo to /yourpath/tsbxrun_mysandbox1.py
  2. Open and edit /yourpath/tsbxrun_mysandbox1.py. Modify userconfig section according to your specific needs.

Sandboxes of TreeSandbox will run as standalone single .py files, each of them contain both userconfig section and the sandbox program code. So that's current deploy & config steps. (We'll make a auto deploy script, for likely we'll have many specific sandboxes)

What Difference with Tree Sandbox

Let's see some examples to get to know about Tree Sandbox. A few words cannot cover it all — just a glimpse.

Example - Two Apps in One Sandbox

Suppose you have two apps, VSCode and MSEdge, which come from same vendor, so you want them run in same sandbox called ms, to enable their better interaction (assuming they will interact with each other).

Tree Sandbox supports <ins><u>placing multiple different apps in same sandbox and provides choose-and-launch method</u></ins>.

Assume that after proper configuration, our host can call MSEdge browser using following command to open GitHub:

tsbxrun_ms.py --app msedge https://github.com   # 1

Now assume we’re going to do coding. Host calls VSCode to edit some files:

tsbxrun_ms.py --app vscode main.c zlib.h  # 2
tsbxrun_ms.py --app vscode app.js  # 3

That’s 3 calls already. Next, assume host calls the in-sandbox browser again to open Linux website in new tab:

tsbxrun_ms.py --app msedge https://www.kernel.org   # 4

Above has assumed the host has made multiple calls to tsbxrun_ms.py. To tell subsequent calls to reuse the sandbox instance started on the first call, we configure the sandbox as "reuseful".

A userconfig for this example looks like (simplified):

uc.sandbox_name = 'ms' 
uc.reuseful = True
uc.apps = [
    d(cmdvec=['/somepath1/microsoft-edge'], appname='msedge'), 
    d(cmdvec=['/somepath2/code'], appname='vscode'), 
]

Example - Partially "Merge" localhost

Other sandboxes offer similar network feature, while we currently have slight advantage.

Assume programs on host listen on local ports 22, 53, and 8000. You do not want to expose 22 to sandbox, but you want sandbox able to access 53 and 8000, and you want the sandbox to access them directly via 127.0.0.1 to avoid configuring subnet gateway IP.

Assume also a program in sandbox listening on port 1080. You want host able to access sandbox's 1080, directly via 127.0.0.1 too, to avoid co

View on GitHub
GitHub Stars10
CategoryDevelopment
Updated1d ago
Forks1

Languages

Python

Security Score

95/100

Audited on Mar 30, 2026

No findings