Skip to content

Security Model

Adi edited this page Oct 18, 2026 · 5 revisions

Security model

Threat model. The model inside the sandbox may be confused, compromised or prompt-injected (for example, by text in the repo or in an issue). It must not be able to:

  • reach the network;
  • read or modify anything on the host beyond its own scratch workspace;
  • escalate privileges;
  • talk to other agents;
  • choose a different model or spend unbounded compute;
  • get code executed outside the sandbox through the results it returns.

Layers

Layer Enforces
Agent container See the full list below.
Per-task gateway See the full list below.
Launcher Clients choose which task and model to run, never how. See the full list below.
MCP server Unprivileged (your uid, read-only rootfs, no caps), 127.0.0.1 only, bearer token on every request; only repos under AGENTBOX_REPOS_ROOT.
Result collection The agent controls its .git (hooks, core.fsmonitor, core.hooksPath, filters in config). agentbox never runs git in it: it uses a trusted shadow git dir and a temporary index over the workspace files, with core.hooksPath=/dev/null and core.fsmonitor=false.

Agent container:

  • NetworkMode none: only lo exists.
  • Read-only root filesystem.
  • CapDrop ALL, no-new-privileges, default seccomp and AppArmor.
  • Runs as uid/gid 64000, which need not exist on the host. If a container escape ever happened, that identity owns nothing.
  • Private IPC, tini as init.
  • Limits: 512 pids, 8 GiB memory (no swap), 4 CPUs, nofile 4096.
  • tmpfs /tmp and $HOME.
  • Mounts exactly its workspace, its gateway socket dir and, optionally, a read-only venv.
  • The image has no package manager, no su or sudo, and no setuid binaries.
  • Optional gVisor: AGENTBOX_AGENT_RUNTIME=runsc.

Per-task gateway:

  • One unix socket per task, mounted into that agent only.
  • Allows only POST /v1/messages and /v1/messages/count_tokens, and only with the task's one-time token.
  • Rewrites model to the task's model.
  • Strips unsupported fields.
  • Meters input and output tokens from the (streamed) responses and enforces a per-task budget (default 20M tokens; answers 403 once exhausted).
  • Never forwards the agent's credentials or arbitrary headers.

Launcher:

  • Workspace and socket paths are derived from the task id (^[0-9a-z-]{1,64}$), resolved, and checked to be inside the data dir.
  • The workspace must be owned by the agentbox user.
  • The command must be claude ....
  • Only an env allowlist passes through.
  • Venvs must live under configured roots.
  • A hard deadline kills the agent even if the MCP server dies.
  • The chown helper mounts only the one workspace and uses chown -R -h, which never follows symlinks.

Verified by tests

scripts/smoke-test.sh checks a live agent container:

  • NetworkMode none and only lo;
  • read-only rootfs;
  • CapDrop [ALL] and CapAdd [];
  • no-new-privileges;
  • runs as the agent uid, from both docker inspect and id -u inside;
  • exactly 2 mounts.

Behavioural probes inside the agent image:

  • CapEff=0, NoNewPrivs=1, Seccomp=2;
  • DNS and HTTPS fail;
  • writing to /usr fails;
  • no Docker socket;
  • no apk, su or sudo;
  • no setuid files.

Git-hook attack test. An agent was told to install pre-commit, post-commit and post-index-change hooks, set core.hooksPath, and set core.fsmonitor to a command that drops marker files. After collection, no hook marker existed anywhere. The fsmonitor marker appeared only inside the sandbox, where the agent ran git itself. Nothing ran in the agentbox container.

Residual risks

  • The launcher holds docker.sock, which is root-equivalent. Mitigations: it has no network, a minimal API, input validation, and it never parses model output. Audit it.
  • The MCP server uses host networking so it can reach 127.0.0.1 model servers. It holds no secrets besides its own token. It mounts your repos root read-write, which it needs to fetch result branches.
  • Model servers run with GPU access on the host network, bound to 127.0.0.1. Another local user could call them. They are not reachable from agents except through a gateway.
  • The agent can read whatever is in the repo you delegate. Don't delegate repos containing secrets you wouldn't show the model. It cannot send them anywhere, but its output (diff and report) comes back to you.
  • Shared-kernel containers. For stronger isolation, use gVisor (runsc) or a VM runtime.
  • Single-user design. Everything binds to 127.0.0.1. Don't expose port 8765.

Clone this wiki locally