Skip to content

Egress Policies

Bryant VanOrden edited this page Sep 1, 2026 · 1 revision

Egress policies

An egress policy constrains what a sandbox can reach on the network. It's set per instance, at create:

{
  "name": "restricted-bot",
  "tier": "standard",
  "egress": {
    "allow": ["api.example.com", "93.184.215.0/24"],
    "deny":  ["1.1.1.1"],
    "block_local": true
  }
}
  • allow — non-empty means allow-list only: everything else is dropped, including a blanket drop of IPv6.
  • deny — hosts/CIDRs to drop, on top of whatever else is permitted.
  • block_local — drops RFC1918, link-local and CGNAT ranges, which is what stops an agent reaching your LAN, your database, or a cloud metadata endpoint.

Fail-closed everywhere: if the policy can't be programmed, the instance doesn't come up. An instance that asked to be restricted never runs unrestricted.

How it's enforced

The same egress.sh nftables program, applied where each driver's traffic actually flows:

  • Container driver: in the sandbox container's own network namespace, before anything the agent controls is listening. The container gets CAP_NET_ADMIN only when it carries a policy.
  • QEMU driver: in the runner's namespace — every connection the guest opens is a SLIRP socket owned by the QEMU process there, dialled to the destination the guest asked for. Nothing inside the guest can see or flush the rules, and the guest is never told a policy exists. This placement is strictly stronger than the container tier's.

DNS and loopback always stay open (nothing resolves without them), and replies to connections opened to the sandbox — health polls, the VNC stream — are accepted statefully, so an allow-list can't strangle the control plane.

Limits, stated plainly

  • Hostnames resolve once, at policy time. A CDN-backed host whose addresses rotate drifts out of an allow-list — use a CIDR or an egress proxy for those.
  • block_local covers IPv4 only. The shipped compose networks are v4-only so this doesn't bite by default; if you enable IPv6 yourself, use an allow-list (which does drop IPv6 wholesale). Full detail in docs/SECURITY.md.
  • On the container driver the rules live in a namespace the container itself holds NET_ADMIN for — root inside the container could still flush them (the sudoers deny-list blocks the obvious route). If tamper-proof egress is the requirement, use the QEMU driver, where that path simply doesn't exist.
  • Egress filtering is off by default. No policy on the instance means no rules programmed.

Clone this wiki locally