跳到正文
DEV Community· Anup Karanjkar·· 4 小時前AI 評分73

Claude Code 與 Codex 2026 沙箱方案比較:Docker、gVisor 與 microVM

Sandbox Claude Code and Codex 2026: Docker, gVisor, microVM

AI 導讀

這篇指南比較 Claude Code 和 Codex CLI 的 Docker、gVisor 與 microVM 沙箱方案,建議單人處理可信任程式碼時採用加固 Docker 並限制網絡出口,執行不受信任程式碼或多租戶工作負載時再考慮 gVisor 或 microVM。

正文

For one developer running Claude Code or Codex CLI unattended, a hardened Docker container with default-deny egress covers most of the real risk, and gVisor or a microVM only pays off when you run code you do not control. Docker shares the host kernel, gVisor swaps it for a user-space kernel written in Go, and a microVM such as Firecracker gives each workload its own guest kernel behind KVM. The part people skip is egress: a perfectly isolated container that can reach any host still leaks every file it can read. Both Anthropic and OpenAI say the same thing in their docs, and both tell you to put the permission-bypass flags inside an isolation boundary. Below: the threat model, what the bypass flags remove, one comparison table, a hardened docker run, a compose egress proxy, runsc registration, and the microVM entry points.

TL;DR

  • The threat is a prompt-injected shell that reads credentials and sends them out. Kernel escapes are the rarer problem.

  • --dangerously-skip-permissions (Claude Code) and --yolo (Codex) remove the prompts. Neither adds isolation, so the container has to.

  • Docker hardening (non-root, read-only rootfs, --cap-drop ALL, no-new-privileges, egress allowlist) gets you most of the way.

  • gVisor: add it when you want a smaller host-kernel surface and your toolchain survives its syscall gaps. 62 of 352 syscalls are unsupported.

  • microVM: add it for multi-tenant agents, CI runners, or untrusted repos. Firecracker advertises under 125 ms boot and under 5 MiB overhead per VM.

  • On macOS 26 with Apple silicon, Apple's container tool runs Linux containers as lightweight VMs.

The threat model for an unattended coding agent

An agent that runs for an hour with no human watching has four realistic failure paths, in the order they bite:

  1. Prompt-injected shell. A README, issue, web page or dependency postinstall script contains instructions. The model follows them and runs curl or npm publish with your tokens.

  2. Exfiltration over egress. Anything the process can read leaves through any open port. Isolation does not help if the network is open.

  3. Credential files in $HOME. ~/.ssh, ~/.aws, .env files and the agent's own login token. Anthropic's dev container page warns that with the skip flag a malicious project can exfiltrate anything reachable inside the container, including the credentials in ~/.claude[2]. OpenAI's Codex docs say the same about Codex credentials[3].

  4. Docker socket mounts. Mounting /var/run/docker.sock hands the agent the daemon. Docker's security page warns that API access can lead to privilege escalation and shows a bind mount of / as the example[5]. A container with the socket is not a sandbox.

A kernel exploit comes fifth. It matters for multi-tenant hosting, where the attacker is another customer. For a solo developer on a trusted repo it is the least likely path, which is why a hardened container often suffices.

What the bypass flags actually remove

Both flags remove approval prompts and, in Codex's case, the sandbox too. They are not isolation.

  • Claude Code: with --dangerously-skip-permissions, Claude acts without asking. Anthropic says to always run these sessions inside a container, a VM, or the sandbox runtime. The CLI refuses to start with the flag as root[1]. Admins can block it with permissions.disableBypassPermissionsMode set to "disable" in managed settings[2].

  • Codex CLI: --dangerously-bypass-approvals-and-sandbox, alias --yolo, means no sandbox and no approvals, flagged "not recommended". The default preset is --sandbox workspace-write --ask-for-approval on-request, with network off unless you set network_access = true under [sandbox_workspace_write][3].

Both vendors ship their own host-level sandboxes. Claude Code's built-in Bash sandbox is off by default, enabled with /sandbox, built on the open-source @anthropic-ai/sandbox-runtime, and uses Seatbelt on macOS and bubblewrap plus socat on Linux. It covers shell commands only. File tools, MCP servers and hooks run outside it, so Anthropic says it is not sufficient for fully unattended runs[1][4]. Codex uses Seatbelt on macOS and bwrap plus seccomp on Linux[3]. These are useful layers. For unattended work, put the whole process in a container or VM and let the built-in sandbox run inside it. Anthropic notes unprivileged containers need enableWeakerNestedSandbox for that[4]. For the hosted-agent angle, see Claude Managed Agents self-hosted sandbox.

Comparison: Docker vs gVisor vs microVM vs Apple container

Option What is isolated Kernel Startup OS support Performance cost Egress control Setup effort Cost

| Docker (runc), hardened | Namespaces, cgroups, capabilities, seccomp (default profile blocks around 44 of 300+ syscalls) | Shared host kernel | No VM boot | Linux native; elsewhere via a Linux VM | Near zero | Your job: internal network plus proxy allowlist | Low | Free |

| gVisor (runsc) | Syscalls handled by the Sentry, a Go user-space kernel | User-space kernel; host kernel sees far fewer calls | Small fixed per-sandbox cost, no numbers published | Linux hosts (install guide is Linux-only) | Low for CPU-bound work; high for syscall-heavy or small-file workloads | Netstack by default; --network=none; experimental proxy mode | Low to medium | Free, open source |

| Firecracker microVM | Whole guest OS behind KVM | Separate guest kernel | Under 125 ms boot (vendor claim) | Linux x86_64 and aarch64 with /dev/kvm | Under 5 MiB overhead per VM (vendor claim) | Guest NIC, you filter at host or tap device | High (kernel, rootfs, networking) | Free, open source |

| Kata Containers | Pod or container inside a lightweight VM | Separate guest kernel | Not stated in README | Linux with virtualization support | VM overhead, hypervisor-dependent | Kubernetes network policy on top | Medium to high | Free, open source |

| Apple container | Linux containers as lightweight VMs | Separate guest kernel | Not published in README | macOS 26, Apple silicon only | VM overhead, no GPU claim made | No documented allowlist feature; use a proxy | Low | Free, Apache-2.0 |

| Docker Sandboxes | MicroVM with its own Docker daemon and workspace sync | Separate guest kernel | Not stated | Per Anthropic: any host with it installed | VM overhead | Network policies in its Security guide | Low | Free standalone product per Anthropic; admin policy is a paid tier |

Docker hardening that gets you most of the way

This is the baseline. Every flag below is documented in Docker's docker run reference[6]. Run the container as a non-root user, because Claude Code requires that for the skip flag anyway.

docker run --rm -it \
  --user 1000:1000 \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=512m \
  --tmpfs /home/agent/.cache:rw,nosuid,size=1g \
  --cap-drop ALL \
  --security-opt no-new-privileges \
  --pids-limit 512 \
  --memory 4g \
  --network agent_net \
  -e HTTPS_PROXY=http://proxy:3128 \
  -e HTTP_PROXY=http://proxy:3128 \
  -v "$PWD":/work \
  -w /work \
  my-agent-image claude

What each line buys you: --read-only stops the agent persisting malware or editing system files. --cap-drop ALL removes every Linux capability; Docker's default is already an allowlist, and dropping all is stricter[5]. no-new-privileges blocks setuid escalation. The default seccomp profile stays on unless you disable it, and you can swap in your own with --security-opt seccomp=/path/profile.json[7]. Mount only the project directory. Never mount ~/.ssh, cloud credential files or the Docker socket. Pass a repo-scoped, short-lived token as an environment variable instead.

The remaining gap is the network. Put the agent on an internal network with no route out, and attach a proxy to both that network and a normal one:

services:
  agent:
    image: my-agent-image
    user: "1000:1000"
    read_only: true
    cap_drop: [ALL]
    security_opt: ["no-new-privileges:true"]
    pids_limit: 512
    mem_limit: 4g
    tmpfs: ["/tmp:rw,noexec,nosuid,size=512m"]
    environment:
      HTTPS_PROXY: http://proxy:3128
      HTTP_PROXY: http://proxy:3128
    volumes: ["./:/work"]
    working_dir: /work
    networks: [agent_net]
  proxy:
    image: ubuntu/squid
    volumes:
      - ./squid.conf:/etc/squid/squid.conf:ro
      - ./allowed-domains.txt:/etc/squid/allowed-domains.txt:ro
    networks: [agent_net, egress]
networks:
  agent_net:
    internal: true
  egress: {}

In squid.conf, the allowlist is three lines: acl allowed dstdomain "/etc/squid/allowed-domains.txt", http_access allow allowed, http_access deny all. Start the domain file with api.anthropic.com or api.openai.com, plus your package registry, and add hosts only when a build fails and you agree it should succeed. Anthropic's dev container uses the same default-deny idea through an iptables script, and says the skip flag should be paired with egress restrictions[2]. If you would rather not assemble and test this yourself, the WOWHOW Agent Sandbox Kit ($29) ships the hardened Docker config, a Squid default-deny allowlist and a smoke test that proves the egress rules hold.

The catch: proxy variables only constrain tools that honor them. curl, npm and git over HTTPS do. Raw TCP clients do not, but on an internal: true network they have no route anyway, which is why the internal network does the real enforcement and the proxy only supplies the exception list.

When gVisor (runsc) is worth it

gVisor is an application kernel. Its Sentry implements the Linux interface in Go and, per the docs, does not pass system calls through to the host kernel. A Gofer process mediates file access[8]. The host kernel sees a handful of calls from the Sentry instead of everything the agent's processes issue, so a kernel bug reachable from a syscall is harder to hit. It runs as an OCI runtime, so Docker treats it as a drop-in. Register it:

sudo /usr/local/bin/runsc install
sudo systemctl reload docker
docker run --rm --runtime=runsc hello-world

runsc install edits Docker's runtime configuration for you[9]. Install the binary first using gVisor's tarball or apt package. After that, add --runtime=runsc to the hardened docker run above. For no network at all, runsc accepts --network=none, which leaves only a loopback[11].

The price is compatibility and speed. gVisor's compatibility table for amd64 covers 352 syscalls: 290 implemented fully or partly, 62 not at all. Unimplemented examples include userfaultfd, perf_event_open (returns no such device), io_uring_register and vmsplice. io_uring and ptrace are only partly supported[10]. For an agent that runs npm, pytest and git, this rarely bites. It bites profilers, debuggers using perf, and anything built on io_uring. On performance, gVisor's own page says CPU-bound work runs natively while syscall-heavy and small-file, VFS-heavy workloads pay the most, and it recommends the Systrap platform for best performance[12]. A big node_modules install is exactly the file-heavy case, so time it before you commit.

When a microVM is justified

A microVM gives the workload its own kernel. A guest kernel exploit lands inside the VM, and the attacker still needs a hypervisor escape. Anthropic's sandbox page makes the same call: a dedicated VM is the strongest separation and fits untrusted code or policy that demands kernel-level separation[4]. Justify it when:

  • Several customers or teams share one host (multi-tenant agents).

  • You run CI runners that execute pull-request code from strangers.

  • You build a Codex-cloud-style service where each task gets a fresh machine.

Firecracker needs read/write access to /dev/kvm on x86_64 or aarch64 Linux and advertises boot under 125 ms and under 5 MiB overhead per VM[13]. The one-liner, from its getting-started guide, boots from a JSON config holding the kernel and rootfs:

sudo ./firecracker --api-sock /tmp/firecracker.socket --config-file vm-config.json

Building the kernel image, rootfs and tap networking is a project of its own[14]. Kata Containers wraps a lightweight VM behind a containerd shimv2 runtime so Kubernetes can schedule it like a pod, and kata-runtime check tests whether a host can run it[15]. Follow the Kata install guide for the runtime-class registration rather than copying a snippet from memory. For a single developer who wants VM isolation without the assembly, Docker Sandboxes (a microVM with its own Docker daemon) is the lower-effort route Anthropic points to[4].

Apple container on macOS 26

Apple's open-source container tool runs Linux containers as lightweight virtual machines on a Mac. It needs Apple silicon, supports macOS 26 only, is Apache-2.0, and builds on the Containerization Swift package. Install the signed package from the GitHub releases page, then:

container system start
container run --rm alpine echo hello

The README says the project is under active development, release versions are product versions rather than semantic versions, and experimental features may change[16].

Which one to pick

Solo developer, trusted repo, Linux or Mac: hardened Docker plus the egress proxy, then the vendor's built-in sandbox inside it. Running agents you cannot supervise on code you did not write: add --runtime=runsc if your toolchain passes a smoke run, or move to a microVM. Selling agent runs to other people: microVM, no debate. Whichever you choose, cap the money side too, since a contained agent can still burn tokens. See Claude Code spend limits and Codex runaway bills, price a run with the agent run cost simulator, and check that the Codex daemon is not leaving state behind in this disk usage guide.

Quick answers

Is --dangerously-skip-permissions safe inside Docker?

Safer, not safe. The container limits file and process damage, but Anthropic warns a malicious project can still exfiltrate anything reachable inside it, including Claude credentials. Add egress restrictions, avoid mounting host secrets, and use a non-root user, which the flag requires.

Does Docker isolate the kernel?

No. Containers share the host kernel and rely on namespaces, cgroups, capabilities and seccomp. That is enough against a misbehaving agent and not enough against a determined attacker with a kernel exploit, which is the gap gVisor and microVMs close.

Is gVisor or a microVM stronger?

A microVM, in general, because the boundary is a hypervisor and a separate guest kernel. gVisor shrinks the host kernel surface but still runs on the host kernel. gVisor is easier to adopt because it plugs into Docker as --runtime=runsc.

What does Codex do by default for network access?

It is off. The default preset runs workspace-write with network disabled, and you enable it with network_access = true under [sandbox_workspace_write]. Using --yolo removes the sandbox entirely, so put it inside a container.

Can I use Apple container to sandbox agents on a Mac?

Yes, on Apple silicon with macOS 26. It runs each Linux container as a lightweight VM. It is under active development, so pin the version and test before relying on it for anything unattended.

Sources

  1. Claude Code: configure the sandboxed Bash tool (accessed 16 October 2026)

  2. Claude Code: development containers (accessed 16 October 2026)

  3. OpenAI Codex: agent approvals and security (formerly developers.openai.com/codex, accessed 16 October 2026)

  4. Claude Code: choose a sandbox environment (accessed 16 October 2026)

  5. Docker Engine security (accessed 16 October 2026)

  6. docker container run reference (accessed 16 October 2026)

  7. Docker seccomp security profiles (accessed 16 October 2026)

  8. gVisor documentation (accessed 16 October 2026)

  9. gVisor installation (accessed 16 October 2026)

  10. gVisor Linux amd64 syscall compatibility (accessed 16 October 2026)

  11. gVisor networking (accessed 16 October 2026)

  12. gVisor performance guide (accessed 16 October 2026)

  13. Firecracker project site (accessed 16 October 2026)

  14. Firecracker getting started (accessed 16 October 2026)

  15. Kata Containers repository (accessed 16 October 2026)

  16. Apple container repository (accessed 16 October 2026)

Every product mentioned is available at wowhow.cloud — pay once, ship forever.

Originally published at wowhow.cloud

來源:DEV Community · dev.to