« Phase 09 README · Warmup · Deep Dive · Principal Deep Dive · Core Contributor · Staff Notes

Phase 09 — Hitchhiker's Guide

The compressed practitioner tour. Read the WARMUP for the mechanism; this is the stuff you say in the meeting.

30-second mental model

An agent runs code and tools a model proposed — untrusted, possibly injected (Phase 10). Once you honor a proposed action, you contain it. Containment is four controls: least privilege (grant only the files/hosts/tools it needs — an allow-list, not a deny-list), filesystem isolation (only an allow-listed slice; .. can't escape — canonicalize then check), egress control (only allow-listed hosts, so it can't exfiltrate), and resource limits (CPU/mem/time/output/ops, so a runaway is bounded). A container is those four via Linux namespaces (view) + cgroups (consumption) + seccomp (syscall muzzle), sharing the host kernel. A microVM (Firecracker) gives each workload its own kernel — stronger, ~125 ms slower. The rule: a denied op never raises and never performs the effect.

The numbers / facts to tattoo on your arm

FactWhy it matters
container = namespaces + cgroups + seccompa process the kernel isolates, not a VM
namespaces = pid/net/mount/userthe container's private view of the kernel
cgroups = cpu/memory/pidsthe meter; pids.max is the fork-bomb defense
seccomp blocks ~44 of ~350 syscallsnarrows the kernel attack surface (the muzzle)
Firecracker cold start ≈ 125 msper-workload kernel at near-container speed
allow-list, not deny-listfails closed; the thing you forgot is denied
canonicalize, THEN checknormpath("/work/../etc")→/etc; escape now visible
/work must not authorize /workshopboundary-match ("/work/"), not startswith
default-deny egress + host allow-listthe anti-exfiltration / anti-SSRF control
resource limit = hard halt; capability = softbudget trips the breaker; one bad op doesn't
inject the clock, never time.time()deterministic + replay-safe (Phase 08)

Framework one-liners

  • Docker / runc — assembles namespaces + cgroups + seccomp + dropped caps from an OCI spec. Knobs: --cap-drop=ALL, --read-only, --network=none, --pids-limit, --memory, --security-opt seccomp=…. Docker's whole agentic bet is secure execution for agents.
  • KubernetesNetworkPolicy (default-deny egress + allow-list), SecurityContext (runAsNonRoot, readOnlyRootFilesystem, drop caps), ResourceQuota, and a RuntimeClass to swap in gVisor/Kata.
  • gVisor (runsc) — a userspace kernel (Sentry) intercepts syscalls; small surface, OCI ergonomics, some syscall overhead.
  • Firecracker — minimal Rust VMM, per-workload guest kernel; powers Lambda/Fargate.
  • seccomp-bpf — a BPF filter the kernel runs on every syscall: allow/deny/kill. The real "check before the effect."
  • E2B / Vercel Sandbox — productized "run the agent's untrusted code": ephemeral, network-restricted sandboxes (Vercel Sandbox = ephemeral Firecracker microVMs).

War stories

  • SSRF via the agent's fetch tool. An agent with an unrestricted fetch read a poisoned web page that told it to fetch http://169.254.169.254/latest/meta-data/…. It lifted the host's IAM credentials from the cloud metadata endpoint and (would have) exfiltrated them. Fix: default-deny egress + a host allow-list that excludes link-local and unlisted hosts — the request never leaves the box.
  • Path traversal out of the "jail." The sandbox confined reads to /work/ with a path.startswith("/work") check. /work/../../etc/passwd sailed through (raw string, no canonicalization) — and /workshop/secrets did too (prefix, not boundary). Fix: normpath then boundary-match against "/work/".
  • Fork-bomb with no cgroups. A coding agent ran generated tests in a container with namespaces but no pids limit. One while True: os.fork() spawned processes until the node fell over and took the neighbors with it. Namespaces are a wall; you still need the cgroup meter.
  • The eval "sandbox." Someone shipped eval(code, {"__builtins__": {}}) as "safe." ().__class__.__bases__[0].__subclasses__() walked the object graph back to os in three lines. In-process is not isolation.

Vocabulary

Capability (unforgeable authority token) vs Linux capability (CAP_SYS_ADMIN, a different thing) · POLA / least privilege · ambient authority · namespace (pid/net/mount/user) · cgroup (cpu/memory/pids) · seccomp-bpf · read-only rootfs · rootless · microVM / Firecracker / VMM · gVisor / Sentry / userspace kernel · path traversal / canonicalize-then-check / TOCTOU · egress allow-list / NetworkPolicy / SSRF · exfiltration · blast radius · default-deny / fail-closed · ephemeral sandbox · hard halt vs soft denial.

Beginner mistakes

  1. Running untrusted code in-process (eval/exec) and calling it a sandbox.
  2. Deny-lists instead of allow-lists (fails open — the forgotten case is permitted).
  3. Prefix path checks without canonicalization (.. escape) or without boundary (/workshop).
  4. Namespaces but no cgroups — filesystem/network jail that a fork-bomb or memory hog defeats.
  5. Unrestricted egress — the exfiltration/SSRF hole that leaks the actual customer data.
  6. Trusting a system prompt to keep the agent in bounds (it's a suggestion, not a boundary).
  7. Reading time.time() for the deadline — non-deterministic, untestable, not replay-safe.
  8. Assuming a container equals a VM in isolation strength (shared kernel = one CVE from escape).