Configure the network egress jail#

The egress jail runs Claude in its own network namespace and blackholes RFC1918 (10/8, 172.16/12, 192.168/16) and link-local (169.254/16) so a compromised or prompt-injected session cannot pivot to internal hosts or lab devices (EPICS IOCs, PMAC). The internet, DNS, and any IPs you allow stay reachable. It is on by default (15. Jail Claude’s egress in a per-process netns with a routing allowlist) and fail-closed. Normal, non-Claude shells keep host networking untouched.

For the design rationale and how it meshes with Claude Code’s native sandbox, see the egress jail and the native sandbox.

Working in an unpromoted workspace?

Running Claude unpromoted is the normal, recommended mode — the shadow and the global integrity guard protect claude in every folder, so a workspace does not need promoting to be safe.

The trade-off is that the just recipes and project commands like /verify-sandbox ship with the claude-sandbox clone, so they are only available when Claude’s working directory is that clone. To use them, cd into the clone (e.g. /workspaces/claude-sandbox), run what you need, then return to your work — dropping back to the clone like this is expected and fine. (Promoting the workspace with just promote makes them available in place, but that is optional.)

Add the one required container device#

The jail needs /dev/net/tun in the container. An installer cannot add a container runArg, so you must add it to your devcontainer yourself:

// .devcontainer/devcontainer.json → runArgs
"runArgs": ["--device=/dev/net/tun"]

Rebuild the devcontainer for it to take effect. install.sh already installs passt (which provides pasta), so that dependency is never the blocker.

Fail-closed: if /dev/net/tun, pasta, or unshare is missing while the jail is on, claude refuses to launch rather than silently falling back to open egress. The error names both the fix and the escape hatch.

Keep a lab device or internal forge reachable#

Device IPs you still need (an EPICS IOC, a PMAC, your internal GitLab) must be punched through the blackhole with allow-ip in the host-global config. Edit the clone conf at .devcontainer/claude-sandbox.conf:

# .devcontainer/claude-sandbox.conf  (installed to /etc/claude-sandbox.conf)
allow-ip = 172.23.142.119   # internal GitLab forge
allow-ip = 172.23.1.3       # an EPICS IOC / PMAC

One bare IP per line; repeat for multiple devices. The shipped default allows Diamond’s internal GitLab (172.23.142.119) so git push to the forge keeps working. allow-ip lives in /etc, not the workspace, so a compromised session cannot widen its own reach.

Apply it the same way as any conf change: re-run ./install, or rebuild the devcontainer (postCreate re-stamps the conf).

Disable the jail#

Two ways; env wins over conf:

  • Per host — uncomment egress-jail = 0 in .devcontainer/claude-sandbox.conf, then re-run ./install (or rebuild).

  • Per sessionCLAUDE_SANDBOX_EGRESS_JAIL=0 claude, or set it in your devcontainer’s remoteEnv.

Disabling restores the open-egress world of 5. Leave network egress open; egress filtering is out of scope: Claude shares the host network namespace, with no per-process firewall.

A note on Channel Access for Claude#

Claude’s private netns has no LAN broadcast domain, so EPICS Channel Access auto-discovery does not work for Claude while jailed — use a unicast EPICS_CA_ADDR_LIST. Normal (non-Claude) shells keep host networking and broadcast.

See also#