How Claude Code and Codex Sandbox Untrusted Code | by Hideaki Takahashi | Jun, 2026 | MediumSitemapOpen in appSign up<br>Sign in
Medium Logo
Get app<br>Write
Search
Sign up<br>Sign in
How Claude Code and Codex Sandbox Untrusted Code
Hideaki Takahashi
12 min read·<br>Just now
Listen
Share
Press enter or click to view image in full size
When you let an AI agent run shell commands in your repository, you are running code that no human wrote and no human reviewed before it executes. The agent might rm -rf the wrong directory, curl | sh something hostile, exfiltrate your ~/.ssh keys, or simply burn your CPU in an infinite loop. A sandbox is the blast wall between "the agent tried something" and "the agent damaged your machine."<br>Press enter or click to view image in full size
Claude Code (Anthropic) and Codex (OpenAI) take different positions on where that wall goes and how thick it is. This post explains the kernel primitives all three draw from, then compares how each assembles them. We also further introduce h5i, which provides stronger soundboxed environments where multiple agents can work toghter and peer-review each other without any conflict.
Part 1 — The primitives<br>Press enter or click to view image in full size
Modern Linux sandboxes are not one feature; they are a stack of independent kernel mechanisms, each closing a different class of escape. Here’s the vocabulary you need.<br>Namespaces<br>Press enter or click to view image in full size
A namespace virtualizes one kind of global system resource so that processes inside see their own private copy. Linux has several:<br>user : UID/GID mappings — lets an unprivileged user be root inside without being root outside.<br>pid: Process IDs — the sandboxed process can't see or signal host processes, and gets its own PID 1<br>net: Network interfaces, routing tables, firewall rules — an isolated net namespace starts with no connectivity except loopback<br>mount: The filesystem mount table — you can bind-mount a custom view of the disk that the host never sees.<br>ipc, uts: System V IPC / hostname — smaller blast radius, isolated for completeness.<br>Bubblewrap (bwrap)<br>Press enter or click to view image in full size
Bubblewrap is a small, audited setuid-or-userns helper that does one job: spawn a process inside a fresh set of namespaces with a custom filesystem view built from bind mounts. You hand it flags like:<br>bwrap --unshare-user --unshare-pid --unshare-net \<br>--ro-bind / / \ # whole disk, read-only<br>--bind /home/me/project /home/me/project \ # writable hole<br>--proc /proc --dev /dev \<br>-- mycommandThe result: mycommand sees the disk as read-only everywhere except the writable holes you punched, can't see host processes, and (with --unshare-net) has no network. Bubblewrap is not a container runtime, and there is no image, no daemon, no layers. It's a one-shot "run this command in a restricted view" tool. Both Claude Code and Codex use it as their Linux filesystem isolator.<br>seccomp (and seccomp-bpf)<br>Press enter or click to view image in full size
seccomp (“secure computing mode”) filters system calls, such as opening a file, opening a socket, forking, loading a kernel module. With seccomp-bpf you install a small BPF program that inspects each syscall’s number and arguments and returns allow, deny (errno), or kill.<br>A sandbox uses seccomp to shut doors that namespaces don’t cover, e.g.:<br>block ptrace (debugger-based escape onto sibling processes),<br>block io_uring_* (a notorious source of kernel-LPE bugs),<br>block mount/umount2 (so the process can't undo your mount setup),<br>block socket syscalls (socket, connect, bind…) for a "no network" mode that doesn't even need a network namespace.<br>seccomp-bpf is static, where the decision is a pure function of the syscall arguments at call time. It can’t, for example, allow connect() only to github.com, and it can't do a DNS lookup from inside a BPF program.<br>seccomp user-notification (seccomp-notify)<br>Press enter or click to view image in full size
This is the powerful, less-common cousin. With SECCOMP_FILTER_FLAG_NEW_LISTENER, instead of the kernel deciding allow/deny itself, the filtered syscall is parked and a supervisor process in userspace is handed a notification file descriptor. The supervisor can inspect the call, do arbitrary work (resolve a hostname, consult a policy, log it, prompt a human), then tell the kernel to allow, fake a return value, or deny.<br>Landlock<br>Press enter or click to view image in full size
Landlock is a newer Linux Security Module (LSM, since kernel 5.13) that lets an unprivileged process sandbox itself with a filesystem (and, in later ABIs, network-port) allowlist.<br>Unlike bubblewrap, Landlock doesn’t remount anything, but it attaches an allowlist ruleset to the current process and all its children: “these paths are readable, these are writable, everything else is denied.” It composes with seccomp and namespaces and is unprivileged-friendly. Different kernels ship different ABI versions (ABI 1 = filesystem; ABI 3+ adds...