Expand description
Sandbox — a generic, process-wide execution boundary (Linux only).
This is not a policy engine. There are no per-bridge rules, no domain
allowlists and no dynamic decisions: the sandbox installs one coarse OS-level
boundary around the whole process, once, at startup. Everything the process
does afterwards — sh.exec, mcp.connect child processes, Lua io.*/os.*,
the HTTP client — runs inside that boundary because Landlock rulesets and
seccomp filters are inherited across fork(2) / execve(2).
§What is enforced
| Axis | Behaviour |
|---|---|
| read / execute | unrestricted (/ is granted ReadFile/ReadDir/Execute) |
| write | denied except for an explicit allowlist (see below) |
| TCP | unrestricted by default; tcp = false denies bind+connect |
| io_uring | io_uring_setup / io_uring_enter / io_uring_register fail with EPERM |
Reads and executes are deliberately left open so that PATH lookups, shared library loading and ordinary tooling keep working — the boundary is about mutation, not secrecy.
The write allowlist is:
- the project root (
--project), - the agent-block state dir (
AGENT_BLOCK_HOME, default$HOME/.agent-block), /tmp,/dev/null,/dev/urandom,/dev/tty,- every path listed in
AGENT_BLOCK_SANDBOX_FS_RW(:-separated).
Entries that do not exist are skipped rather than treated as an error, so a shared config can list paths that are only present on some machines.
io_uring is blocked because it lets a task submit file and socket operations through a shared ring, bypassing the syscall-level view a seccomp filter has. Landlock still covers ring-submitted filesystem operations, but denying the setup syscall keeps the boundary easy to reason about.
§Failure model
Fail-closed: when the sandbox is requested but the kernel enforces nothing
(no Landlock support), apply returns an error and the caller is expected
to abort startup. A partial enforcement of the default rights (older
Landlock ABI, e.g. no Truncate) logs a warn! describing what was dropped
and continues — the filesystem boundary is still real in that case. Two
things are never downgraded to a warning: an unresolvable project root (the
primary write grant) and an explicitly requested TCP denial on a kernel
whose Landlock ABI predates network rights — both abort startup.
§KNOWN LIMITATIONS
- Linux only. On other platforms
applyreturnsSandboxError::Unsupported; there is no silent no-op. - UDP and DNS are not restricted. Landlock’s network rights cover TCP
bind/connect only, so
tcp = falsedoes not stop UDP traffic (including DNS resolution) or unix-domain sockets. - io_uring is unusable inside the sandbox, including for dependencies that would otherwise opportunistically use it.
- TCP is a single on/off switch. There is no per-host or per-port granularity, by design — that would be policy, not a boundary.
- The boundary is process-wide and irreversible. It cannot be relaxed
later in the process lifetime, and it must be installed before any thread
that needs to be covered is spawned (Landlock’s
restrict_selfapplies to the calling thread and its future children). - The io_uring deny only exists on x86_64 and aarch64. On other Linux
architectures no seccomp filter is compiled and the deny is skipped with a
warn!; the Landlock filesystem boundary still applies there.
Structs§
- Sandbox
Config - Resolved sandbox knobs.
Enums§
- Sandbox
Error - Errors returned by
apply.
Functions§
- apply
- Install the execution boundary for this process.