docs/book/src/security/sandboxing.md
The runtime executes tool invocations inside an OS-level sandbox when one is available. The sandbox restricts filesystem access to the workspace, limits network reachability, and removes access to the parent process's secrets.
This is distinct from the autonomy system and command allow-lists. Those are policy layers that decide whether a tool may run; the sandbox is a mechanism layer that confines what a running tool can reach if it does run.
ZeroClaw picks the best available backend at startup:
| Platform | Preferred order |
|---|---|
| Linux | Landlock (kernel 5.13+) → Bubblewrap → Firejail → Docker → none |
| macOS | Seatbelt (native) → Docker → none |
| Windows | AppContainer (experimental) → Docker → none |
| Any | Docker (if daemon reachable) → none |
You can force a backend:
[security.sandbox]
backend = "bubblewrap" # or "landlock", "firejail", "docker", "seatbelt", "noop"
Set backend = "noop" to disable sandboxing entirely (part of YOLO mode).
/usr, /lib, /etc (read-only), and explicitly-listed extra paths/tmp~/.ssh, ~/.aws, ~/.config (except ZeroClaw's own), anything in [autonomy] forbidden_pathsBy default, sandboxed tools have full network egress but no inbound listening.
For tighter control:
[security.sandbox]
network = "allowed-domains"
allowed_domains = ["api.openai.com", "api.anthropic.com", "api.github.com"]
Or network = "none" to block network entirely (useful for pure-local tools).
The sandbox passes through only the env vars listed in [autonomy] shell_env_passthrough. Inherited secrets do not reach sandboxed tools unless explicitly passed.
[security.sandbox] memory_limit_mb (default unset — no cap)[security.sandbox] max_subprocesses (default unset)shell)The Linux-native path. Zero setup, kernel-enforced, very low overhead. Requires kernel 5.13+.
Limitations:
forbidden_paths enforced via path-based rules, not inode-based, so a clever symlink can sometimes escape (we resolve links before handing to Landlock to mitigate this)bwrap)User-namespace-based sandbox from Flatpak. Confines filesystem and can block network. Require bubblewrap installed.
# install
sudo apt install bubblewrap # Debian/Ubuntu
sudo pacman -S bubblewrap # Arch
sudo dnf install bubblewrap # Fedora
SUID-based sandbox. Older but widely available.
sudo apt install firejail
Firejail's default profile is fairly permissive; we apply a custom profile bundled with ZeroClaw.
Works anywhere Docker does. Runs each tool invocation in an ephemeral container (the zeroclawlabs/tool-runner image).
[security.sandbox]
backend = "docker"
image = "zeroclawlabs/tool-runner:latest"
Pros: strong isolation, works on any OS. Cons: per-invocation container startup cost (100–500 ms). Best for production deployments where the overhead is acceptable.
Native macOS sandbox (sandbox-exec). Profiles are SBPL — we bundle one for tool runs. Works transparently on macOS 10.11+.
Limitation: some CLI tools (older versions of git, some Homebrew-linked binaries) don't cooperate with Seatbelt's file-access rules. If you see "Operation not permitted" errors from the agent's shell calls on macOS, check if the tool needs broader filesystem access and consider switching to Docker.
noopNo sandboxing. Tools run with the full privileges of the ZeroClaw service user. This is what YOLO mode enables. Loud, obvious, intentional.
Hardware tools (GPIO, I2C, SPI, USB) need device access that most sandboxes block by default. When hardware features are enabled, the sandbox profile is relaxed for specific device paths:
[security.sandbox]
allow_devices = ["/dev/gpiochip0", "/dev/i2c-1", "/dev/spidev0.0", "/dev/ttyUSB0"]
Lock this down to only the devices your agent actually needs.
zeroclaw service status and the journal; the auto-detect logs which backends it tried.docker group).docker pull zeroclawlabs/tool-runner.crates/zeroclaw-runtime/src/security/detect.rscrates/zeroclaw-runtime/src/security/sandbox/ (one file per backend)[security.sandbox] block in crates/zeroclaw-config/src/schema.rs