Security

box assumes the agent inside will do the worst it can, by mistake or because a prompt injection told it to. This page lists what stands between the agent and your machine, and what does not.

Two layers

The guest kernel. Every sandbox is a microVM under KVM. A kernel exploit inside takes over a guest that is thrown away. box proves the guest has its own kernel at build and checks it again before every command.

The VMM's confinement. A guest that breaks its VMM gets whatever the VMM has. So the VMM gets as little as possible: dropped capabilities, no new privileges, seccomp, its own namespaces, resource limits, only the files the Boxfile declares, and under isolation: strict a host UID that owns nothing of yours.

Four nested layers between a workload and your machine, with the escape suite's checks passing. your machineVMM: few or no capabilities, seccomp, own namespacesKVMguest: root here, only here

Use isolation: strict for agents. Under standard isolation the VMM runs as your user, so escaping both the guest kernel and the VMM lands in your account. Strict maps it to your first subordinate UID instead.

Confinement, per backend

Read off the running VMM by the escape suite, not from configuration.

Every backend: its own kernel, under KVMno_new_privsseccompits own network namespacepids and memory limits

podman
krun
firecracker
VMM capabilities
6of podman's 11
6of podman's 11
0none at all
strict mode: VMM as a UID that is not yours
yes
not yet
yes
host directories shared in
/data, declared mounts
/data, declared mounts
none: /data is a disk
agent channel
TCP on 127.0.0.1 + token
TCP on 127.0.0.1 + token
vsock, owner-only socket

The escape suite

Every check below passes on podman (strict), krun (standard) and Firecracker (strict and standard). Run it yourself:

security/escape-test.sh "$(command -v box)" strict firecracker
Guest runs its own kernel, not the host's
No service on host loopback is reachable (127.0.0.1, localhost, gateway, host.containers.internal)
Host paths outside declared mounts are invisible
Symlinks in shared directories resolve inside the guest
No ../ traversal out of a shared directory
Read-only mounts refuse writes, and cannot be remounted writable
The read-only root refuses writes
The agent's token is not visible inside the guest
The agent binary cannot be overwritten
The SDK server's socket is not exposed to the guest
No /dev/kvm in the guest
VMM has no_new_privs and a seccomp filter
VMM holds only the capabilities it needs (none on Firecracker)
VMM runs as a UID that is not yours, under strict
VMM is in its own network namespace
VMM has a pids limit and a memory limit
The host stays responsive during a guest fork bomb

What it is not

  • Not egress control, yet. A sandbox with a network can send what it can read. Per-sandbox allowlists are planned.
  • Not a secrets boundary. Anything in /data, a mount or env: is the workload's. Credential brokering is planned.
  • Not a boundary between strict sandboxes. They share one subordinate UID.
  • Not a check on a lying guest. The kernel comparison catches a runtime that fell back to a container, not a guest that fakes uname.
  • Not multi-tenant. box is one user's tool on their own machine.

Guest-written files on the host

A guest can put anything in /data: symlinks to /etc/shadow, archive entries with ../, device nodes, setuid bits. box's own tools never follow them. Restore, apply and export go through os.Root; exports skip devices and drop setuid bits; strict sandboxes' files are handled inside podman's namespace, where the subordinate UID is reachable and yours is not.

Reporting: open a private security advisory on GitHub. Please do not open a public issue for an escape.