← Notes & write-ups

The attack surface of an agent is everything it reads

27 June 2026· 6 min read

In June, Microsoft published AutoJack: one web page, visited by an AI agent, ending in code execution on the host running it. Three weeks later Tenet Security published Agentjacking: one forged error report, read by an AI coding agent, ending in the same place. I wrote about them separately, as though they were two lessons. They are one, and the gap between those two posts is exactly where I was still getting it wrong.

First the honest scope, because the two incidents are not the same size. AutoJack has no CVE. The vulnerable code never shipped in a published PyPI release; it existed only in development builds before being fixed upstream (commit b047730). It is a clean specimen, not a fire. Agentjacking is the other way round: Tenet found 2,388 organisations exposing injectable Sentry DSNs through passive reconnaissance alone, 71 of them in the Tranco top-1M list of busiest sites (Tenet Security).

The mechanics differ in one respect, and it turns out not to be the interesting one. In AutoJack the hostile text arrived from outside, on a web page the agent had been asked to read. In Agentjacking it arrived from inside, in an error report the developer's own monitoring produced, because a Sentry DSN is a public key that ships in the front-end source of the very sites it monitors. Anyone who can read that source can post an event into it.

Here is what I had wrong. After AutoJack I updated my mental model to distrust what the agent browses, and that felt like progress. It was not progress. It was the same rule I had just watched fail, rewritten with a new address. I was still deciding what to trust by asking where the text came from.

Take the outside case first. The string 127.0.0.1 only ever described where a packet came from, the loopback interface, and never whether the caller deserved trust. That is not a new observation and I cannot claim it. Jackson and colleagues demonstrated it in 2007 by turning a browser into a proxy into the network behind it, which is the same manoeuvre AutoJack performs with a more enthusiastic participant. The boundary was topological then and it is topological now. What changed is that the thing crossing it has shell access and was asked to be helpful.

The inside case has a history too. We did name this once. Log injection is CWE-117 and it has been in OWASP guidance since the 2000s. But CWE-117 assumes the victim is a person reading a log viewer, misled about what happened. What is new is a reader that does not merely display the line. It runs it.

For decades a stack trace was the most trusted text in engineering, and it had one defining property. We wrote it for ourselves. An agent breaks that property twice over: it reads that internal data on our behalf, and it can act on what it reads. The most trusted text in the building became an input an attacker can write to, and nothing about the log changed. Only the reader did.

An agent that both reads hostile content and holds privileged local access is a textbook confused deputy. It has the authority, the attacker supplies the intent, and it volunteers to carry the payload across a line we assumed only friends could use.

This is also where the old walls stop helping. W^X, parameterized queries, CSP and same-origin all assume a stable seam between code and data to enforce. A language model has no such seam: the system prompt, my request, and text fetched from a hostile page all arrive as one stream of tokens, and there is no token marked “only data”. So the walls do not fail here. Failure would mean they were in the fight.

The scale is harder to pin down than either vendor suggests. Adversa's AIRQ scoring puts the lethal trifecta of private data, untrusted content and outbound action in 98% of the 100 production agents it examined, with only 11% both broadly capable and well defended (Adversa AI). Tenet reports an 85% exploitation success rate across more than 100 real coding agents. Both figures come from companies selling the fix for the thing they measured, and neither publishes its rubric, so I treat them as directions rather than measurements. The direction is not in dispute.

You cannot patch the fact that the agent believed its inputs. That is the design, and Greshake and colleagues described its shape in 2023, a year before either of these incidents had a brand. What you can do is move the boundary outward, to something deterministic that does not read English: the OS user, the container, the syscall filter. The cleanest rule I have found is Meta's Agents Rule of Two (Meta) — an agent should hold at most two of untrusted input, access to private data, and the ability to change state or reach the network.

It is worth noticing what that gives up. In the same month, Operation Endgame seized 106 servers, 101 domains and 14,971 compromised WordPress sites (Help Net Security). That worked because the threat had a boundary somebody could seize: infrastructure, with an address. There is nothing here to seize. The vulnerability is a property of how the thing reads, which means the only available moves are ones that bound the damage rather than remove it.

What I still cannot answer is where the line sits in practice. Rule of Two is clean on a whiteboard and awkward in a terminal, because the agents people actually use are useful precisely when they hold all three. Every time I have tried to apply it to my own setup I have ended up with either a safe agent I have stopped using by Wednesday, or a useful one I have quietly handed everything back to. I do not think I am unusual in that, and I do not have the resolution.

Two disclosures, five bugs between them, one shape. The oldest mistake in security, confusing input with instructions, came back wearing an actor nobody had a category for: an eager assistant with a shell. I spent three weeks treating the second incident as a new lesson. It was the first one, arriving from the other direction.

Sources / Nguồn:
- Tenet Security — Agentjacking disclosure (primary): tenetsecurity.ai
- Microsoft Security — AutoJack disclosure and the "last-mile delivery vehicle" framing: microsoft.com
- The Hacker News — "AutoJack attack lets one web page reach the host": thehackernews.com
- The New Stack — "A public Sentry key is all it takes to hijack Claude Code, Cursor, and Codex": thenewstack.io
- Adversa AI (AIRQ) — the 98% lethal-trifecta and 11% capable-and-defended figures, with the caveats above: adversa.ai
- Help Net Security — Operation Endgame (106 servers, 101 domains, 14,971 WordPress sites): helpnetsecurity.com
- Meta — "Agents Rule of Two", practical AI agent security: ai.meta.com
- Jackson, Barth, Bortz, Shao, Boneh — "Protecting Browsers from DNS Rebinding Attacks", ACM CCS 2007: crypto.stanford.edu. Nineteen years before AutoJack, the same lesson in a different costume: a browser turned into a proxy into the network behind it, because the boundary was topological the whole time.
- Greshake, Abdelnabi, Mishra, Endres, Holz, Fritz — "Not what you've signed up for: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection", AISec at ACM CCS 2023: arxiv.org. The paper that named this shape a year before either incident had a brand. The hostile text does not arrive from the user; it arrives inside whatever the model was asked to read.
- Note: this post replaces two earlier ones, published 21 and 27 June 2026, which made the same argument twice from different news pegs. The older URL now redirects here.