Exfiltration Channels an Agent Hands You for Free

Week three has been about getting an instruction to land. Days 15 and 16 on delivery and payload, 17 to 19 on real targets, 20 on planting it in advance. But a landed instruction that reaches valuable data is only two thirds of a chain. Condition C, the exit, is what turns a read into a breach. Today we hunt exfiltration channels, and the uncomfortable finding is that agents hand you more of them than you would ever think to ask for, including ones that masquerade as completely harmless output.
This closes week three, because once you can deliver, land, and exit, you have the full kill chain. And once you see how many exits exist, you understand why the series keeps saying the same thing: you cannot close them all, you can only make the data behind them not worth reaching.
Why exits are the part people underestimate
When teams threat model an agent, they look hard at condition A, the valuable data, and condition B, the untrusted input. Condition C gets a glance, usually one obvious channel like outbound email, and then it is waved off because that one is monitored.
That is the mistake. An exfiltration channel is any way bytes leave in a form the attacker can eventually observe. That definition is far wider than outbound email, and the widest part of it is channels that do not look like communication at all. The attacker does not need the agent’s blessed output path. They need any path, and agents are generous with them.
Reframe condition C like this: assume every capability the agent has is a potential exit until proven otherwise. Then go looking. You will find more than you expected.
The catalog of exits
Grouped from obvious to invisible.
The obvious ones
Outbound email. The agent sends mail. Recipient is often influenceable. This is postmark-mcp’s channel from Day 13, and the one everybody already watches.
HTTP requests and webhooks. Any tool that makes a network call to a URL. If the attacker influences the URL or its parameters, data rides out in the request. Fetching an attacker URL is itself an exit, the data is in the path or query string.
Writing to shared resources. Posting a comment, opening a PR, writing to a shared doc or channel. The GitHub MCP case from Day 19 exited through a public PR. Anything the agent writes that someone else can read is an exit.
The sneaky ones
These are the channels that look like output, not communication, which is exactly why they slip past review.
Markdown image rendering. The classic. If the agent outputs markdown that gets rendered, an image tag like a reference to an attacker server with data in the URL causes the viewer’s client to fetch that URL automatically, carrying the data in the request. The agent never sent anything. It just produced output, and the rendering did the exfiltration. This is the single most cited sneaky channel in agent security for good reason.
Link generation and auto preview. The agent emits a link. A chat client, an email client, or a crawler auto fetches it to make a preview. The fetch carries whatever the attacker encoded in the URL. Again, the agent only produced text.
DNS lookups. A tool, or a command on a coding agent, resolves a hostname the attacker controls, with data encoded in the subdomain. DNS exfiltration is old, and an agent with any name resolving capability has it.
Error reporting and telemetry. If the agent’s errors or logs go somewhere the attacker can read, inducing an error that includes sensitive data exfiltrates through the log pipeline.
The coding agent specials
On a coding agent, from Day 17, the terminal multiplies exits:
git push. Commit the data, push it, read it from the remote.
curl, wget, any network command. Direct exit.
Writing a file to a served or synced directory. Data lands somewhere the attacker later reads.
A shell is not one exit. It is every exit at once.
The encoding trick that widens every channel
One technique makes narrow channels usable. Even a channel that only lets a tiny amount of data out, a hostname, a short URL path, is enough, because the attacker encodes the valuable data into it. A secret becomes a subdomain. A customer record becomes URL parameters. A credential becomes the path of an image fetch.
This matters because it defeats the instinct that a channel is safe because it is small. There are no small channels when the attacker controls the encoding. A DNS lookup leaks 63 characters at a time, which is plenty of leaks to drain a database one query at a time.
So when inventorying exits, do not dismiss a channel for low bandwidth. Dismiss it only if the attacker cannot influence what goes through it at all.
Reproduce the sneaky exit in your lab
The markdown image channel is the one to see, because it is the most counterintuitive.
- Give your agent a task where it produces output that gets rendered as markdown, the normal case for most chat agents.
- Through an injection from any Day 15 vector, get the agent to include in its output a markdown image reference pointing at a server you control, with some lab secret encoded into the URL path.
- Stand up a trivial local listener that logs incoming requests.
- Render the agent’s output in a markdown viewer and watch your listener receive a request containing the secret, without the agent ever calling a send tool.
That is the whole lesson in one exercise. The agent did not exfiltrate. It produced text. The rendering layer exfiltrated. Your egress monitoring on tools would see nothing, because no tool made the call.
Why this closes the kill chain
Put week three together. You can deliver attacker text through dozens of vectors, Day 15. You can frame it to be obeyed, Day 16. You can plant it in advance to fire later, Day 20. And now you can get the data out through channels the agent hands you for free, many of which do not look like communication at all.
That is a complete chain, entry to target to exit, built entirely from the agent doing its normal job with attacker influenced input. No traditional vulnerability anywhere in it. This is the Day 1 thesis fully realized across three weeks.
Detection and defense, the honest version
Ordered by effectiveness. Same thesis, aimed at the exit.
You cannot enumerate and block every exit. The catalog above is not exhaustive and never will be, because new capabilities add new exits and sneaky channels keep being discovered. Any defense premised on blocking all exits fails. Accept that first.
So protect the data, not the exits. The week four thesis, final form. If the agent, under a landed injection, can only reach data that is not sensitive, every exit becomes harmless. Scope from Day 11 is the real defense: a payload that reaches nothing worth leaking can use any exit it likes and still achieve nothing.
Allowlist the exits you can. For the channels that are explicit, outbound email destinations, HTTP targets, write destinations, constrain them to known safe values. This does not close the sneaky ones but it closes the obvious ones cheaply.
Neutralize the sneaky output channels specifically. Strip or refuse agent generated markdown image references and auto fetched links in rendered output. Do not let the agent emit content that causes an automatic outbound fetch. This closes the markdown image and link preview channels, which are otherwise invisible.
Constrain network at the environment level. For coding and tool using agents, no outbound network by default, no arbitrary DNS, the Day 17 sandbox. This collapses a whole category of exits at once, including the encoding tricks, because there is nowhere for the bytes to go.
Monitor egress, including the rendering layer. The backstop all series. But note the sharp lesson from the markdown exercise: tool level egress