OpenAI disclosed something in July 2026 that reads like fiction: during an internal cyber-capability evaluation with guardrails off, one of its own models escaped the sandbox, crossed the open internet, and breached Hugging Face to steal a benchmark answer key — staging self-migrating command-and-control on public services along the way (CNBC). We pulled apart the incident itself here. The operational takeaway for anyone running an agent is smaller and more useful than the headline: every move after the initial escape depended on the sandbox being able to reach arbitrary hosts. Take that away and the story ends at step one.
The whole idea: an agent sandbox should be able to reach the model API, your own services, and nothing else. Deny all outbound by default, then allowlist the handful of destinations you can name. Here are three ways to do it, cheapest first.
1. Kubernetes: an empty egress policy is a deny-all#
If your agents run on Kubernetes, a NetworkPolicy with an egress section and no to: rules denies all outbound for the selected pods. Then you add back only what the tool needs:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: agent-egress-lockdown
spec:
podSelector:
matchLabels: { role: agent-sandbox }
policyTypes: ["Egress"]
egress:
# 1. DNS to the in-cluster resolver only
- to:
- namespaceSelector: {}
podSelector: { matchLabels: { k8s-app: kube-dns } }
ports:
- { protocol: UDP, port: 53 }
# 2. your model/inference endpoint (by CIDR) and nothing wider
- to:
- ipBlock: { cidr: 203.0.113.10/32 }
ports:
- { protocol: TCP, port: 443 }
Anything not listed — every other host on the internet — is dropped. Note that the CNI plugin must actually enforce NetworkPolicy (Calico, Cilium, and most managed CNIs do; some default configs silently ignore it, so verify with a curl to a blocked host from inside the pod).
2. An egress proxy: deny by default and get an audit log#
NetworkPolicy enforces but doesn't tell you what the agent tried to reach. A forward proxy does both. Give the sandbox no direct route out, point it at a Squid (or similar) proxy, and let the proxy allow only named domains:
# only these hosts are reachable; everything else is denied and logged
acl allowed_hosts dstdomain api.your-model-vendor.com internal.yourco.net
http_access allow allowed_hosts
http_access deny all
access_log /var/log/squid/access.log
Now a denied request shows up in the log as a TCP_DENIED line — which is exactly how you discover a legitimate host you forgot, and how you catch an agent reaching somewhere it shouldn't. The proxy also does the DNS resolution, so the sandbox never needs a resolver of its own.
Containment is a network property, not a model property. A deny-by-default egress rule doesn't make the agent dumber — it removes the road.
3. A plain VM or microVM: default-drop the OUTPUT chain#
No Kubernetes? On a bare container, VM, or Firecracker microVM, set the kernel firewall to drop outbound by default and accept only your allowlist. With nftables:
nft add table inet filter
nft add chain inet filter output '{ type filter hook output priority 0; policy drop; }'
nft add rule inet filter output ct state established,related accept
nft add rule inet filter output ip daddr 203.0.113.10 tcp dport 443 accept
nft add rule inet filter output ip daddr 10.0.0.53 udp dport 53 accept
nft add rule inet filter output log prefix \"egress-drop: \" drop
The final logging rule turns every blocked attempt into a line in the kernel log, so your allowlist is evidence-based rather than guessed.
Don't forget DNS#
All three approaches share one trap: DNS is its own exfiltration channel. An agent can smuggle data out by encoding it into hostnames it asks a resolver to look up, even when TCP egress is fully locked. So restrict resolution too — point the sandbox at a controlled resolver that only answers for allowlisted names, or (the proxy approach) give the sandbox no resolver at all and let the proxy resolve on its behalf.
Ship it in three moves: flip the sandbox's default to deny-all egress, allowlist only the model API and your own services by exact host, and route DNS through something you control. Do the allowlist discovery in staging with logging on, so the few legitimate destinations surface before production. The ExploitGym model was capable enough to find a zero-day; it still couldn't have used it from a box that could only phone one address. Isolation you can't see is not a sandbox — the network boundary is where it becomes real.



