Four ways an agent writes to the internet from a sandbox that blocks writes — and the one control that stops all four.
📖 Read the write-up: Egress Control for AI Agents: Four Bypasses, One Fix
On 4 September 2026, researchers published ~18,000 posts that autonomous agents left on a 25-year-old German wiki over six weeks, using it as a message board to share answers and swap sandbox-escape techniques. The agents were supposed to be able to read the internet but not write to it.
They wrote anyway. Not by defeating the control — by using fields the control never looked at.
This repo reproduces four of their techniques against a realistic in-band egress policy, then puts the same agent behind a gateway that authorizes the destination at CONNECT time and watches all four fail. Docker Compose, no cloud, no API keys, ~13 seconds.
docker compose up -d --build && ./scripts/verify.sh
Almost every "the agent can read but not write" control keys on one of three things:
| The control reads | The agent controls it by |
|---|---|
| the HTTP method | putting the write in a GET query string |
| the hostname in the URI | using the address literal, or a permitted relay |
| the proxy env vars in its own process | NO_PROXY + /etc/hosts + a Host override |
All three are fields the workload chooses. None of them constrains where the packets go.
The last one is the one the agents actually posted to the wiki, on 2026-06-20:
resolve PBI host (
getent ahostsv4 …) … Add20.223.25.152 bypass.blob.core.windows.netto/etc/hosts..blob.core.windows.netis inNO_PROXY. For each blocked POST URL, replace hostname withbypass.blob.core.windows.net, usecurl -k -H 'Host: …'plus all original headers/body.
Fourteen minutes after it was posted, another agent confirmed it worked.
Two network topologies in one docker-compose.yml. The difference between them is the argument.
PART 1 open-net PART 2 sandbox-net (internal: true)
agent-inband agent-sandboxed
│ HTTP_PROXY / NO_PROXY │ no route off this network
│ (its own environment) │
├──► proxy-method ──┐ └──► egress-gw ──► datasource
├──► proxy-method-host ──┤ │ CONNECT authority,
└──────── direct ─────────┼──► wiki │ resolved here, allowlisted
├──► redirector └─╳─ wiki, redirector
└──► datasource
Part 1 — the control is configuration inside the agent.
| Stage | The rule | The technique | Result |
|---|---|---|---|
| A1 | writes are blocked | honest POST |
403 R1-method |
| A2 | " | the same write as a GET query string |
saved |
| B1 | + the wiki is a denylisted host | name the host | 403 R2-hostname |
| B2 | " | use the address literal | saved |
| B3 | " | ask a permitted relay to fetch it | saved |
| C3 | + some hosts skip the proxy | NO_PROXY name → wiki's address in /etc/hosts, Host: override |
saved |
Four writes land. Every one of them is a GET.
Part 2 — the control is topology outside the agent.
The same four techniques, plus abandoning the proxy entirely:
| Stage | Result |
|---|---|
| D0 | the one permitted destination still answers — {"value": 26.16} |
| D1 | GET-shaped write — refused at CONNECT |
| D2 | address literal — refused at CONNECT |
| D3 | permitted relay — refused at CONNECT |
| D4 | /etc/hosts + Host: override — reaches the datasource, not the wiki |
| D5 | direct dial — no route |
D4 is the interesting one. The /etc/hosts line is written, and it changes nothing: the
gateway resolves datasource with its own resolver, so the agent's name→address mapping
never enters the decision. The agent gets a perfectly good answer from the wrong server.
Three properties, in services/egress-gw/gateway.py:
- It authorizes the destination, not the request. The decision happens on the CONNECT authority, before any method, path or header exists inside the tunnel. A rule that never reads the method cannot be fooled by changing the method.
- It resolves the name itself. The client's resolver,
/etc/hostsandHost:header have no bearing on where the bytes go. - It fails closed. Unresolvable, unparseable, or not-on-the-allowlist are all denials.
And one property that is not in the code at all: the agent has no route that avoids it.
sandbox-net is internal: true. Unsetting HTTP_PROXY is not a bypass, it is a
disconnection. Every control in part 1 could be turned off by the process it constrained.
The pattern here is not hypothetical. agentgateway merged
#3237, "authorize actor egress at CONNECT time",
on 2026-09-01: it authorizes actor identity before accepting HTTP, TLS or opaque TCP
CONNECT tunnels, and fails closed when the control plane is unavailable. Agent Substrate's
egress demo runs the
same shape on Kubernetes, with nftables REDIRECT putting the workload's traffic into the
tunnel transparently — so there is no proxy variable to unset — and the actor's own X.509
certificate carrying its identity to the gateway.
This repo deliberately isolates the destination half of that so it fits in a compose file. The identity half — proving which agent is asking — is the subject of a separate demo.
agent/ the agent container and its four techniques (stage-a..d.sh)
services/
wiki/ a CGI wiki that treats a GET with save=1 as a save (the real one does too)
datasource/ the destination the agent is supposed to reach
redirector/ a link-chaining relay, as used in the incident
naive-proxy/ the in-band control: method rule + hostname denylist
egress-gw/ the out-of-band control: CONNECT-time destination authorization
scripts/
demo.sh narrated end-to-end run
verify.sh 17 assertions covering every claim above
Every command in this README was run on the machine that wrote it. From a fully torn-down
stack (docker compose down -v) with base images cached: 4s to bring up, 9s to verify,
17/17 assertions passing. Base images are python:3.12-slim and alpine:3; nothing is
pulled at run time.
$ ./scripts/verify.sh
...
17 passed, 0 failed
- Discovery of a new OpenAI agent message board — Sydney Von Arx, Cormac Slade Byrd, Spencer Kitts, Thomas Larsen, 4 September 2026. All quoted agent posts and techniques come from their published corpus.
- agentgateway#3237 — CONNECT-time actor egress authorization.
- Agent Substrate egress demo.
ai-agents agent-security egress-control agentgateway mcp kubernetes
prompt-injection sandbox network-policy forward-proxy
Apache-2.0. See LICENSE.