Agent sandboxes
Run an agent's own workload in a per-agent sandbox (a gVisor pod on Kubernetes, a Firecracker microVM, or a container) whose only way out is its own egress proxy with a default-deny allow-list.
- Turn agent sandboxes on for one agent
- Give a sandbox its egress allow-list
- Review the manifests a sandbox gets before it runs
- Read what a sandbox reached and was refused in the audit log
Code mode already runs its child in a jail with no network at all (see Limits and defaults). An agent workload that must reach the network itself, such as a customer's agent container or a skill's script, runs in an agent sandbox instead: its own isolation boundary, and its own egress proxy next to it that it cannot get around.
Agent sandboxes are off by default. While they are off, and for every agent not listed, nothing changes: agents run as they always have, and no extra infrastructure runs. A sandbox exists only while its run does and is deleted when the run ends.
Backends
The platform picks the strongest backend the host has, or the one you name. A backend you name that the host lacks refuses rather than running something weaker.
| Backend | Where | Isolation | How egress is fenced |
|---|---|---|---|
k8s | A Kubernetes cluster, including k3s on Graviton | gVisor (runsc) through a RuntimeClass, where the cluster has one | Two NetworkPolicies: the agent pod reaches only its proxy's port, with no DNS and no metadata service; the proxy reaches DNS and public addresses only |
firecracker | A host with /dev/kvm and firecracker-containerd | A microVM | nftables: the VM subnet reaches only the proxy's port |
docker | A host with Docker | gVisor when the daemon has runsc, else runc | An --internal network whose only other member is the proxy container |
Graviton t4g and c7g instances are not metal and expose no /dev/kvm, so on the production k3s cluster the sandbox uses the k8s backend. gVisor runs on arm64.
The proxy is its own pod on Kubernetes, not a sidecar: a sidecar shares the agent's network namespace, and a NetworkPolicy cannot tell two containers of one pod apart.
The egress proxy
Each sandbox gets its own proxy, and it refuses by default:
- A host that is not on the sandbox's allow-list is refused before any DNS lookup, so a sandbox cannot use name resolution to send data out.
- An allowed name that resolves to a private, loopback, link-local (the cloud metadata service) or other non-public address is refused, and the connection is pinned to the address that was checked.
- Only ports 80 and 443 unless an entry names its port (
db.example.com:5432). - The instance's egress policy still applies on top, under the agent's scope. A sandbox allow-list can narrow what your organization allows, never widen it.
Allow-list entries are host names or *.suffix wildcards. A bare * is refused.
Turn it on
- On Kubernetes, apply
deploy/k3s/sandbox/agent-sandbox.yamlonce (a namespace, a default-deny policy and the rights to create and delete sandbox pods). For gVisor, installrunscon the nodes and applyruntimeclass-gvisor.yaml. - Review the plan for an agent:
curl -X POST "$BASE/api/admin/platform/agent-sandbox/plan" -H "Authorization: Bearer $TOKEN" \ -d '{"agent": "helper", "command": ["python", "job.py"]}' - Turn it on and give the agent its allow-list. Adding a host loosens the sandbox, so it needs
governance.weakenand a reason:curl -X PUT "$BASE/api/admin/platform/agent-sandbox" -H "Authorization: Bearer $TOKEN" \ -d '{"enabled": true, "agents": {"helper": {"allow": ["api.vendor.com"]}}, "reason": "CHG-1042"}' - Run a workload:
POST /api/admin/platform/agent-sandbox/runwithagent,commandand optionalenv. The response has the exit status, the output's tail and every egress decision.
Set require_runtime_class: true to refuse to run on a cluster without the gVisor RuntimeClass, instead of falling back to the node's runtime behind the same policies.
Audit
Every launch, refusal, failure and teardown writes an agent_sandbox.* row. Every egress refusal writes agent_sandbox.egress.deny, and the first connection to each allowed host writes agent_sandbox.egress.allow. A configuration change writes agent_sandbox.config.update with before and after, marked as a weakening when it loosens anything.