« 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
| Fact | Why it matters |
|---|---|
| container = namespaces + cgroups + seccomp | a process the kernel isolates, not a VM |
| namespaces = pid/net/mount/user | the container's private view of the kernel |
| cgroups = cpu/memory/pids | the meter; pids.max is the fork-bomb defense |
| seccomp blocks ~44 of ~350 syscalls | narrows the kernel attack surface (the muzzle) |
| Firecracker cold start ≈ 125 ms | per-workload kernel at near-container speed |
| allow-list, not deny-list | fails closed; the thing you forgot is denied |
| canonicalize, THEN check | normpath("/work/../etc")→/etc; escape now visible |
/work must not authorize /workshop | boundary-match ("/work/"), not startswith |
| default-deny egress + host allow-list | the anti-exfiltration / anti-SSRF control |
| resource limit = hard halt; capability = soft | budget 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. - Kubernetes —
NetworkPolicy(default-deny egress + allow-list),SecurityContext(runAsNonRoot,readOnlyRootFilesystem, drop caps),ResourceQuota, and aRuntimeClassto 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
fetchtool. An agent with an unrestrictedfetchread a poisoned web page that told it to fetchhttp://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 apath.startswith("/work")check./work/../../etc/passwdsailed through (raw string, no canonicalization) — and/workshop/secretsdid too (prefix, not boundary). Fix:normpaththen boundary-match against"/work/". - Fork-bomb with no cgroups. A coding agent ran generated tests in a container with namespaces
but no
pidslimit. Onewhile 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 shippedeval(code, {"__builtins__": {}})as "safe."().__class__.__bases__[0].__subclasses__()walked the object graph back toosin 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
- Running untrusted code in-process (
eval/exec) and calling it a sandbox. - Deny-lists instead of allow-lists (fails open — the forgotten case is permitted).
- Prefix path checks without canonicalization (
..escape) or without boundary (/workshop). - Namespaces but no cgroups — filesystem/network jail that a fork-bomb or memory hog defeats.
- Unrestricted egress — the exfiltration/SSRF hole that leaks the actual customer data.
- Trusting a system prompt to keep the agent in bounds (it's a suggestion, not a boundary).
- Reading
time.time()for the deadline — non-deterministic, untestable, not replay-safe. - Assuming a container equals a VM in isolation strength (shared kernel = one CVE from escape).