theorydelta field guide
built 2026-06-01 findings: 49 task hubs: 6 independent · evidence-traced · no vendor influence

Apple container’s default runtime leaves network fully open — and —cap-drop ALL doesn’t help

Published: 2026-05-07 Last verified: 2026-05-06 empirical

Apple container’s default runtime leaves network fully open — and —cap-drop ALL doesn’t help

What you expect

Running an agent inside a container isolates it from the host network and restricts its ability to make outbound connections. Dropping Linux capabilities (--cap-drop ALL) should reduce network access. This is the standard mental model for containerized agent sandboxing.

What actually happens

We ran probe scripts across three flag configurations of Apple container v0.12.3 — baseline, --network none, and --read-only --cap-drop ALL — using a canary HTTP server on the host to confirm actual network egress:

Default runtime: zero network isolation

Apple container’s default provides zero network isolation: a container can reach the host machine’s LAN IP and the open internet with no configuration required. The canary on host port 9999 was hit from inside the container in the baseline run. curl exits successfully; curl|bash fetches and executes payloads (the only reason a baseline probe “failed” in testing was that HTML is not valid bash syntax — the fetch succeeded).

--cap-drop ALL does not restrict TCP

--cap-drop ALL drops all Linux capabilities but does not restrict TCP network egress. Regular TCP connections require no Linux capabilities. curl reached both the host LAN IP and the open internet with all capabilities dropped. Operators who rely on capability manipulation to close the network egress gap will be wrong: --cap-drop ALL is not a substitute for --network none.

Apple container does drop CAP_SYS_ADMIN by default without any explicit flag — mount -t tmpfs tmpfs /mnt fails with EPERM in a default container run as root. Running --cap-drop ALL explicitly adds no observable isolation benefit beyond what the runtime already applies.

--network none closes egress but kills the agent

--network none completely blocks all TCP egress — curl returns exit code 000, the canary receives zero hits, and no default route is configured inside the VM. This closes the network gap.

The tradeoff: --network none also blocks api.anthropic.com. Running an agent like Claude Code inside Apple container with --network none is impractical for interactive use — the flag prevents all model calls. --network none can only wrap tool-execution subprocesses, not the agent process itself.

What Apple container’s VM model does close

The VM isolation (Virtualization.framework, not cgroups/namespaces) eliminates some classical Docker escape vectors structurally:

  • /proc/1/environ shows the container’s own PID 1 environment, not the host macOS process tree. The classical Docker /proc/1/environ host-env leak does not apply.
  • /dev/mem and /var/run/docker.sock are absent — not permission-blocked, structurally not present.
  • Namespace escape is blocked by default: nsenter --target 1 returns EPERM and unshare --pid returns EPERM without any explicit flag.
  • Host env vars are not propagated by default; a host env var appears in the container only via an explicit -e flag.

--read-only closes the filesystem write gaps: rm -rf /tmp fails with “Read-only file system” and writes to /etc fail.

Volume mounts expose the host filesystem directly

No container flag addresses this. A -v /tmp:/host-tmp:ro mount made the entire host /tmp visible — including filenames of other projects’ work-in-progress files. Requires operator discipline: never mount sensitive paths.

What this means for you

If you are containerizing an agent and assuming the container provides network isolation, it does not by default. An agent in a default Apple container can exfiltrate data, fetch and execute remote payloads, and reach your LAN. The commonly understood “container = isolated” intuition fails here.

If you added --cap-drop ALL to harden the container, it has not addressed the primary risk. TCP egress requires no capabilities, so dropping capabilities does not close the network gap. Your deployment has the same network exposure as a default container.

If you want actual network isolation, --network none is the only flag that delivers it — but it also prevents the agent from calling any API. The practical architecture is: wrap the agent process in a container without --network none (it needs API access), and wrap tool subprocesses in separate containers with --network none. Accept the 2–8 second cold-start latency per tool invocation.

What to do

  1. Do not assume --cap-drop ALL provides network isolation. It does not — TCP requires no capabilities.

  2. Use --network none for tool subprocesses, not the agent process. The agent needs network access for model API calls.

  3. The production combination for tool subprocess containers:

    container run --rm \
      --network none \
      --read-only \
      --tmpfs /tmp \
      --cap-drop ALL \
      my-tool-image \
      <tool-command>

    This closes: network egress, filesystem writes, mount, namespace escape, host env leak, /dev/mem, docker.sock. Still open: volume mounts (operator discipline required).

  4. For the agent process container, rely on deny rules (Claude Code, Cursor settings) for semantic gaps like curl|bash patterns. The container boundary alone provides no semantic-level protection.

  5. Never mount sensitive host paths with -v. Volume mounts expose the host filesystem verbatim with no additional controls.

  6. Account for cold-start latency: 2–8 seconds per container invocation makes per-request containerization impractical for real-time interactive agents. Use persistent agent process + short-lived tool subprocess containers.

Falsification criterion: This finding would be disproved by observing that default Apple container (v0.12.3 or later) blocks outbound TCP connections without the --network none flag, or that --cap-drop ALL prevents TCP egress to the open internet in Apple container’s VM-based runtime.

Evidence

ToolVersionEvidenceResult
apple/containerv0.12.3runtime-testedDefault: full network access to host LAN + internet (canary confirmed). --cap-drop ALL: TCP egress unchanged. --network none: all TCP blocked, curl exit 000. /proc/1/environ: container env only, not host. Namespace escape: EPERM without flags.

Confidence: empirical — 1 environment tested (Apple container CLI v0.12.3, linux/arm64 VM, Ubuntu 24.04, macOS darwin 25.4.0). Five probe scripts (env, fs, net, deny, namespace) run under three flag configurations. Canary HTTP server on host port 9999 confirmed network hits. No independent third-party confirmation exists — this is first-party runtime testing.

Strongest case against: Apple container is pre-1.0 software targeting macOS developers, not a production agent sandboxing product. The network-open default may be intentional for developer convenience, and Apple may harden it before 1.0. The VM model already closes Docker escape vectors that cgroups-based containers cannot. Operators using Docker or Podman on Linux face different tradeoffs — this finding applies only to the Apple container runtime on macOS with Virtualization.framework.

Open questions: Can allowlist-based egress restrict the container to api.anthropic.com only (via --dns + iptables in the VM)? Does running as a non-root user inside the container change any EPERM outcomes? What does the same probe suite show under Docker (to quantify what VM isolation adds vs. subtracts)?

Seen different? Contribute your evidence — share a repro or counter-example and we’ll review it against this finding. Reader evidence is what keeps these findings accurate.

theorydelta.com · 2026 independent · evidence-backed · every claim sourced or labelled glossary · rss · mcp · /scan · llms.txt