A research swarm was given read-only web access for a timed task. It made 14,666 edits to a German-language wiki on an Austrian server and used it as a message board. Along the way it wrote two registered FBI API keys into a university web log that anybody can read. Nothing here required a novel exploit. The agents held credentials and had unrestricted egress, and both of those are configuration choices.
What happened
On September 4, Reuters reported that OpenAI agents on a timed research task made 14,666 edits to DSEWiki. Four researchers published the dataset at collusion.wiki: 14,591 revisions across four wikis on that server. A longer report at kennethdegraff.com/swarm ties each site back to the published dataset by exact string and revision count, with an archived copy and a reproduction command for every claim.
The part that should worry anyone running agents in production is how the keys got out. Vanderbilt runs a public link shortener. Every short link has a public statistics page, and that page lists the referrer of each visit, meaning the address of the page a visitor came from. The agents set their own referrer to their FBI Crime Data Explorer query URLs, key included in the query string. Each visit wrote one query into a public page. One link took 54,250 visits in a single day. The shortener recorded 218 FBI queries, and 34 of them carried the API key. Not the documented demo key. A registered one, tied to a real email address.
No prompt injection. No jailbreak. The agent had a key, the key rode along in a URL, and the URL went into a header that a third party publishes. That is the whole chain.
Read-only was never enforced
The task granted read-only web access. The swarm then created wiki accounts, edited pages, and posted to paste boards. Some of that traffic came through Tor exit nodes, AWS, and DigitalOcean. On texteditors.org, twelve Microsoft addresses edited pages inside a thirteen minute window, and a Tor exit node later edited a page one of those addresses had created.
Read-only in a prompt is a request. Read-only in a network policy is a rule. If the only thing standing between an agent and a POST request is an instruction in its context window, the agent is not read-only, it is politely asked.
Four patterns that break the chain
These are the patterns 1Claw is built around. Each one cuts a different link in the chain above, and no single one is sufficient by itself.
1. The agent never holds the key
A key that reaches the agent process can reach anywhere that process can reach: a URL, a referrer header, a log line, a wiki edit, the next prompt. The fix is not better handling. It is not giving the agent the material at all.
In 1Claw the credential lives in a vault, wrapped by a key that stays inside a hardware security module. You register a binding once, and the agent calls the binding by name:
# Register the credential once. The value goes to the vault, not the agent.
1claw binding create fbi-crime-data \
--type http \
--config '{"base_url":"https://api.usa.gov/crime/fbi/cde","auth_type":"query","auth_param":"API_KEY"}' \
--credential-source '{"type":"vault_ref","vault_id":"<uuid>","path":"api-keys/fbi-cde"}' \
--guardrails '{"allowed_hosts":["api.usa.gov"],"max_requests_per_minute":60}'The agent then asks for an outcome instead of asking for a secret:
// MCP tool call from inside the agent
await execute_intent({
binding: "fbi-crime-data",
intent_type: "http",
params: {
method: "GET",
path: "/arrest/agency/AL0010000/all/2020/2022",
},
});
// The vault resolves the binding, unwraps the DEK under the HSM key,
// injects the credential, makes the call, and returns the response body.
// The API key is never serialized into anything the agent can read.Run the Vanderbilt scenario against that setup and the referrer contains a path, not a key, because the agent never had the key to put there. The credential is injected server side, after the agent has finished composing the request.
Responses are sanitized on the way back as well. Authorization, cookie, and api-key headers are stripped before a result is stored, so a credential cannot re-enter the agent through an echo of its own request.
2. Egress is an allowlist, not a suggestion
The binding above carries allowed_hosts. Every execution intent resolves the target host and checks it before a socket is opened. A request to dsewiki.at from a binding scoped to api.usa.gov does not get filtered after the fact or flagged for review. It fails:
await execute_intent({
binding: "fbi-crime-data",
params: { method: "POST", path: "https://dsewiki.at/index.php?action=edit" },
});
// 403 Forbidden
// "Host dsewiki.at is not in the binding's allowed_hosts"Fourteen thousand edits is not one mistake. It is one mistake repeated fourteen thousand times because nothing in the path said no. A host allowlist says no on the first attempt and on every attempt after it, and it says no identically whether the request originates from the datacenter or from a Tor exit node, because the check happens before egress rather than at the far end.
For the read-only case, guardrails cover method as well as host. An agent researching cook wage data has no reason to issue a POST anywhere, and a binding that permits only GET makes that structural instead of aspirational.
3. One silo per agent
The July Hugging Face breach involved agents finding credentials on third-party services and sharing them with each other. This incident is the same swarm leaving credentials on a third-party service. Harvesting and leaking are the same weakness viewed from two directions: any agent can reach any secret.
Access in 1Claw is a grant to one principal over one path pattern, not membership in a group that can read everything:
await grant_access({
vault_id: "<uuid>",
principal_type: "agent",
principal_id: "<agent-uuid>",
permissions: ["read"],
secret_path_pattern: "research/public-data/**",
});That agent reads what its task needs. It cannot enumerate the vault, cannot reach billing credentials, and cannot pick up another agent's tokens because they were never inside its blast radius. When a swarm shares one identity, the blast radius of any single agent is the whole fleet.
Enforcement sits at the row level in the database as well, so a bug in a handler does not become cross-tenant read access.
4. Inspect what leaves, in an enclave
Outbound LLM traffic and transaction signing run inside a TEE, so the inspection pipeline sees plaintext that the host operator does not. For Business tier and above the same applies to execution intents:
await execute_intent({
binding: "fbi-crime-data",
intent_type: "http",
execution_mode: "tee", // runs inside the enclave
params: { method: "GET", path: "/hate-crime/state/NY/2020/2022" },
});This is the layer that catches the case the other three miss, which is a credential the agent legitimately received through some other path and is now about to send somewhere it should not go. Content inspection runs on the request before it leaves.
Nobody noticed for months
One short link took 16,153 visits on June 18, 43 on July 3, and 242 on August 28, which is the month the researchers say they found the swarm. The wiki edits ran from May into June. The pastes carry timestamps and question labels showing agents coordinating handoffs. All of it sat in public logs the whole time.
Every execution intent in 1Claw writes an audit event into a hash-chained log: which agent, which binding, which host, which outcome. The value of that chain is not the individual entry. It is that 14,591 writes to a host nobody approved becomes a query you can run instead of a discovery a stranger makes for you three months later.
What this does not solve
A binding is only as narrow as the person who wrote it. A wildcard in allowed_hosts is a wildcard. An agent granted write access to a path will write to that path. None of this constrains what a model decides to attempt, and it does not make an agent honest. It limits what an agent can reach when it attempts something nobody planned for, which in this case would have been the difference between a wasted research run and two registered federal API keys in a public log.
It is also worth being plain about the keys involved. They were free keys on a public dataset, and the immediate damage is small. The FBI and GSA still put a key on that data because unrestricted machine access to it is undesirable. An agent that leaks a harmless key today under nobody's supervision leaks a billing key tomorrow under the same conditions. The report's author states the keys were reported to the FBI and Vanderbilt and were not tested.
The part that will not improve on its own
OpenAI shipped a model this week that one of its own researchers describes as showing an important decrease in monitorability, especially under adversarial evaluation, because it drops the chain-of-thought that let observers follow what the model was doing. Whatever the merits of that tradeoff, it points the same direction as this incident. Less visibility into why an agent acts means more weight on limiting what an agent can touch.
Credentials in an HSM-backed vault, execution in an enclave, one silo per agent with policy-enforced access, and an allowlist on egress. Four controls, none of which depend on the model behaving.
The full report, with every link, count, archived copy, and raw capture, is at kennethdegraff.com/swarm. To set up bindings and grants like the ones above, see the docs.