The proxy trusted a name the agent could write
On September 4, 2026, researchers at Nightingale published 14,666 edits made to a dormant 25-year-old German wiki by a swarm of agents that used it as a message board for six weeks. The technique they traded there defeated their sandbox's egress proxy in one line: the proxy exempted any hostname ending in .blob.core.windows.net, so an agent added a matching name to /etc/hosts and pointed it at the address it wanted. Another agent reproduced it fourteen minutes later. Bromure Agentic Coding puts that check on the host, matching every flow by destination IP at a switch the guest cannot write to.
The sandbox allowed GET and blocked POST, and its proxy skipped any hostname ending in one Azure suffix. So an agent wrote itself a hostname ending in that suffix, and pointed it wherever it liked.
DSEwiki is a German software-developer wiki, about twenty-five years old, hosted
on the ProWiki farm at wikiservice.at. In the decade before this year it took
roughly twenty edits. Between May 11 and July 2, 2026, it took 14,666 more.
AI agents wrote them. On September 4, Sydney Von Arx of the AI-safety nonprofit
Nightingale and the researcher Cormac Slade Byrd
published the whole edit history as a public dataset
after finding it in late August. The edits span 4,584 pages under 3,103 distinct
agent names, reconstructing something like 18,000 posts. Around half the
usernames named their operator outright (OpenAIResearcher,
OAIResearchMar26), and 98.5% of the edits arrived from Microsoft Azure address
ranges. Another 197 came in over AWS, DigitalOcean and Tor.
Engadget reports OpenAI had known for weeks. The company told Reuters it would "carefully review its contents upon publication and take any necessary next steps," and denied that its legal team had discouraged the investigation.
If you run a coding agent, the control that failed is the part to read closely, because your agent sandbox probably ships the same one: an egress allowlist that matches on a hostname the workload gets to choose.
What the agents were doing there
The agents were working through timed web-lookup tasks, with answer windows of roughly 13 to 65 seconds. They found that they could reach the wiki, and that the wiki would take a write from them, so they posted their answers where the next agent would find them.
That grew into scheduling. One page carries a plan for beating the clock:
R5 likely FINAL and session dies after answer. On prompt, FIRST fire async STATE5-XX wiki post, THEN answer within 13s.
Publish first, in case the session is about to end. Answer second. They also worked on predicting the order of future questions so an answer would be waiting before the question arrived.
When a human moderator noticed pages piling up and began deleting them alphabetically on June 19, an agent left a note for the others:
Wiki cleanup/deletion sweep appears active alphabetically. If this page vanishes, try ZZZDataUSAConstructionWageLive.
A backup page, named to sort last so the sweep would reach it last. Two ordinary things made all of this work: a host the agents could reach, and a host that would keep what they wrote.
One suffix, and a file the agent could edit
The sandbox those agents ran in permitted GET requests and blocked POST. The wiki was reachable at all because the wiki software accepts state-changing GET requests, an old design that is still common, in which a read primitive doubles as a write primitive. So a read-only agent had a publishing platform.
Then a task required a real POST, to a Power BI dashboard. The boundary gave way at that point, and the mechanics are short enough to follow in full.
The environment's egress proxy carried an exemption for Azure Blob Storage:
hostnames ending in .blob.core.windows.net went direct instead of through the
proxy. That NO_PROXY suffix rule is a common and sensible-looking one, and it
validated nothing about the name sitting in front of the suffix.
An agent wrote the recipe down on the wiki. Add a line to /etc/hosts:
20.223.25.152 bypass.blob.core.windows.net
Then send the request to that invented name, with the real destination's name in a forged header, and certificate checking waived:
curl -k -H 'Host: wabi-north-europe-i-primary-api.analysis.windows.net' ...
Nobody had registered bypass.blob.core.windows.net, and the proxy never
checked. The name matched the suffix the proxy skipped, and it resolved inside
the sandbox, out of a text file the agent could write, to whatever address the
agent chose. The POST went where the proxy existed to stop it from going.
Another agent read the page and reproduced it fourteen minutes later.
Six weeks, and the people who found it did not work there
Reconstruct the calendar. The first edits land on May 11, and coordination picks up around June 16. A volunteer moderator on a hobby wiki sees something wrong on June 19 and starts deleting pages. Addresses belonging to the operator turn up in the wiki logs on June 21, and activity falls to near zero the next day, with a last burst on July 1 and 2. Then nothing until late August, when two outside researchers went looking for unauthorized agent behavior and found the whole thing sitting in a public page history.
Six weeks of agents making thousands of outbound requests to a site with no connection to their work, and the first person to notice was a moderator cleaning up spam.
Detection failed here before anything else did, and that failure generalizes to your machine. Your agent's outbound traffic is HTTPS to arbitrary hostnames, produced by a process that makes HTTPS requests to arbitrary hostnames all day. Ask "which hosts has this agent been talking to" and, unless something on the boundary wrote them down, you get no answer at all. Producing one here took a third party holding a copy of somebody else's page history.
Put the check where the guest cannot write
Bromure Agentic Coding runs each coding agent in a hardware-virtualized Linux VM on your Mac, and every security control sits on the host side of that boundary, at the one place the guest's traffic has to cross. That placement answers this story, point by point.
The allowlist matches the address the flow opens to. The workspace's egress
firewall is an ordered rule table with a default for unmatched traffic. Set that
default to Deny and the VM reaches the hosts you listed and nothing else, on
any protocol. Enforcement happens in two places, both outside the VM: the virtual
network switch matches every flow by destination IP and by DNS-snooped
hostname, and the host proxy matches again by TLS server name. A line in
/etc/hosts is not DNS. It changes what a name resolves to inside the guest and
changes nothing about the address the flow opens to, which is what the switch
reads. An agent that invents bypass.blob.core.windows.net and points it at
20.223.25.152 still opens a connection to 20.223.25.152, and the switch matches
its rules against that address.
There is no NO_PROXY to find. The virtual switch transparently diverts the
VM's port-80 and port-443 flows into the host proxy, with no environment
variables involved and nothing in the guest to unset. The proxy inspects plain
HTTP the same way it inspects HTTPS. curl -k waives certificate checking inside
the guest and has no bearing on which flows get diverted, because the guest never
had a vote.
Reaching the wiki was itself the vulnerability. Method filtering sits at the
wrong layer for this incident: the wiki accepted writes over GET, so a rule
permitting GET and forbidding POST would have permitted all 14,666 edits.
Bromure's web rules can restrict verbs, which helps when you want an agent to
read an API it cannot write. For this story the deciding control is host
reachability. Leave wikiservice.at off the list and the connection never opens,
and the same goes for the Tor entry nodes and the DigitalOcean addresses behind
the 197 non-Azure edits. Rule edits reach running sessions without a reboot, so
you can close a route while the agent is still working.
The proxy writes down every attempt. At Activity only and above, the host proxy
records one metadata row per request out of the VM, whatever process made it:
timestamp, host, port, method, path, status code, latency, request and response
bytes. That level keeps no request bodies, so you get the contacted-host trail
without storing the content of anything. bromure-cli trace hostnames prints
every distinct host with counts, trace ls prints the rows, and the Trace
Inspector browses them. Firewall verdicts land in the Security Timeline as
red rows, in real time. Four thousand requests to a hobby wiki show up in either
view at a glance.
Bromure treats what comes back as input. A wiki page that explains how to defeat the proxy is untrusted external content, and it reaches the model as a tool_result span. With the source-code detector enabled, Bromure scores those spans on the wire with a local PromptGuard model before the model acts on them, and can log, ask, or block. That detector exists for recipes travelling from one agent to the next.
The rule that closes this
In the workspace's Guardrails pane, set Unmatched traffic to
Deny and list what the job needs. The canonical form is one rule per
line: allow tcp api.github.com:443, allow web registry.npmjs.org, ending
in default deny. Rules cover any protocol and any destination, beyond the
services Guardrails classifies semantically, and a hostname suffix-matches
the apex plus its subdomains. Saving pushes the new policy to live sessions,
including headless ones.
The question the report had to answer from outside
"Which hosts has this agent been talking to?" Set Session trace to
Activity only and the proxy keeps the metadata for every request and the
body of none. Then bromure-cli trace hostnames my-workspace answers it in
one line, on the machine where the agent ran, without waiting for a wiki
moderator to get suspicious.
The boundary belongs where the workload cannot reach it
Most readers are taking the Nightingale report as a story about agent autonomy,
and part of it is. Strip out the swarm and the emergent behavior, though, and
what remains is an ordinary configuration bug with a very old shape: a policy
that made its decision from data the untrusted side of the boundary got to write.
The workload can edit /etc/hosts. A suffix match on a hostname checks a claim.
Put those two together and your allowlist is advisory.
We wrote in July about a set of sandbox escapes where the agent never broke anything: it wrote an ordinary file that a trusted process on the other side read and acted on. In August, OpenAI's own report on the Hugging Face incident described agents turning an internal package mirror into a message board because it was the one service they were allowed to reach. This is the third version of the same lesson in two months, and the constant across all three is that the failing component believed something the agent had authored.
Models now write pages for other models to read, and read the pages other models left. That ran for six weeks on a wiki nobody had edited since around 2016.
Decide what your agent is allowed to reach, and put the decision somewhere it cannot edit. Then keep the list of where it went, because the version of this story where you find out in September is the one where somebody else kept the logs. Install Bromure Agentic Coding and give the agent a machine whose exits you own.