docs/sandboxing.md
Mise supports lightweight process sandboxing for mise exec and mise run, inspired by zerobox. Sandboxing restricts filesystem, network, and environment variable access with granular controls. No Docker required, minimal overhead.
Any --deny-* or --allow-* flag implicitly enables sandboxing:
# Full lockdown — no writes, no network, no env vars
mise x --deny-all -- node script.js
# Block network only
mise x --deny-net -- npm run build
# Block writes except to ./dist
mise x --allow-write=./dist -- npm run build
# Block everything, allow specific exceptions
mise x --deny-all --allow-read=. --allow-write=./dist --allow-net=registry.npmjs.org -- npm install
| Flag | Description |
|---|---|
--deny-all | Block reads, writes, network, and env vars |
--deny-read | Block filesystem reads (system libs and tool dirs still accessible) |
--deny-write | Block all filesystem writes (except /tmp) |
--deny-net | Block all network access |
--deny-env | Block env var inheritance (only PATH, HOME, USER, SHELL, TERM, LANG pass through) |
--allow-read=<path> | Allow reads from specific path (implies --deny-read for everything else) |
--allow-write=<path> | Allow writes to specific path (implies --deny-write for everything else) |
--allow-net=<host> | Allow network to specific host (implies --deny-net for everything else) |
--allow-env=<var> | Allow specific env var through (implies --deny-env for everything else). Supports wildcards: --allow-env='MYAPP_*' |
These flags work with both mise exec (mise x) and mise run.
Tasks defined in mise.toml can declare sandbox permissions:
[tasks.build]
run = "npm run build"
deny_net = true
allow_write = ["./dist"]
[tasks.lint]
run = "eslint ."
deny_all = true
allow_read = ["."]
[tasks.install]
run = "npm install"
deny_all = true
allow_read = ["."]
allow_write = ["./node_modules"]
allow_net = ["registry.npmjs.org"]
CLI flags on mise run override task-level config:
# Run with task's declared sandbox
mise run build
# Override: also allow network to a specific host
mise run --allow-net=registry.npmjs.org build
When filesystem restrictions are active, certain paths remain accessible so tools can function:
/usr, /lib, /lib64, /bin, /sbin, /etc, /dev, /proc, /sys, /tmp, /nix, /snap, /home/linuxbrew/System, /Library, /usr, /bin, /sbin, /dev, /etc, /var/run, /tmp, /private, /opt/homebrew, /nix~/.local/share/mise/installs/.../tmp (and /private/tmp on macOS)/dev (for /dev/null, /dev/tty, etc.)--allow-write paths are implicitly readable--allow-read paths include system essentials above| Feature | Linux | macOS |
|---|---|---|
| Deny/allow reads | Landlock | Seatbelt |
| Deny/allow writes | Landlock | Seatbelt |
| Deny all network | seccomp | Seatbelt |
Per-host network (--allow-net=<host>) | Not supported (v1) | Seatbelt |
| Env filtering | Built-in | Built-in |
| Docker support | Yes | N/A |
Filesystem sandboxing uses Landlock (available since Linux 5.13). Network sandboxing uses seccomp-bpf to block inet socket creation while allowing Unix sockets.
If Landlock is unavailable or cannot apply filesystem restrictions, the command fails.
Limitation: Per-host network filtering (--allow-net=<host>) is not supported on Linux in v1. On Linux, --allow-net falls back to allowing all network access. This works on macOS via Seatbelt.
Uses Apple's sandbox-exec (Seatbelt) with a generated profile. Supports all features including per-host network filtering.
Sandboxing is not currently supported on Windows. A warning is printed and the command runs unsandboxed.
mise x --deny-write -- bash untrusted-script.sh
mise x --deny-net -- make build
mise x --deny-all --allow-read=./src --allow-write=./dist node@20 -- node build.js
# Only pass through env vars starting with MYAPP_
mise x --allow-env='MYAPP_*' -- node app.js
# Allow multiple patterns
mise x --allow-env='MYAPP_*' --allow-env='NODE_*' -- node app.js
[tasks.test]
run = "npm test"
deny_net = true
deny_write = true
allow_write = ["./coverage", "./node_modules/.cache"]
allow_env = ["NODE_*", "npm_*"]