Senior · Core path · 7 chapters
Data exfiltration channels
Markdown image URLs, links, tool parameters; URL allowlisting and content-rendering policy
If these channels are not treated as an egress boundary, a harmless-looking response can turn the UI or tool layer into an attacker-controlled network client.
Read these first
What you will know
Exfiltrate data through a markdown image URL in a test system
A markdown image URL causes the client to fetch a URL the model chose, carrying data in the path.
Configure and test a renderer that treats model output as untrusted, rejecting raw HTML, unsafe URL schemes, and implicit fetches
Schemes such as javascript and data, plus SVGs and redirecting URLs, can bypass a policy that checks only ordinary HTTP links.
Implement URL allowlisting for rendered content
Allowlisting must cover the final destination and redirect behavior, not merely the hostname present in the model's original text.
Trace a canary secret through a link, tool parameter, and outbound request, identifying the first boundary that permits it
Each channel may cross a different trust boundary, so blocking image fetches alone does not prevent leakage through tools or link handling.
Audit what your UI will render from a model without asking
Include previews, link unfurling, image proxying, redirects, and tool-call side effects in the inventory; user clicks are not the only trigger.
Chapters
- 1
Data exfiltration through rendered markdown
Data exfiltration is private data leaving a system and arriving somewhere an attacker can read it, and the first channel a chat product hands an attacker is its own markdown renderer. The same secret in the same URL has two very different exploitabilities depending on the markup around it: an image is fetched the instant the message renders, with nobody involved, while a link waits for a user to choose something suspicious. Building the image payload against a test system makes the difference concrete, and it explains why blocking images and keeping links is a real purchase rather than a cosmetic one.
- 2
Model output as untrusted markup
A renderer that accepts whatever the model emits is an attacker-controlled client. Rejecting raw HTML and permitting only http and https closes the obvious holes and leaves the awkward ones: javascript and data URLs, inline SVG that can reference external resources, and anything that produces an implicit fetch. Here you configure and test that policy, and see why sanitising SVG puts you in an arms race with a format designed to be a document.
- 3
Allowlisting the final destination
Validating the host that appears in the model's output is not validating what gets fetched, because an allowlisted host can redirect, forward or proxy on demand. Worse, your own CDN and your internal dashboards often serve user-supplied content or accept parameters an attacker can read back, so a request landing inside the allowlist can still reach them. This chapter builds a policy that satisfies a screenshots-and-dashboards product without pretending 'internal' means safe.
- 4
The tool-argument channel
Strip the renderer to plain text — no images, no links — and the outbound path moves to requests the agent makes itself: a search query, a webhook body, a file path. No renderer sees those. When a canary turns up inside a web_search query sent to a third-party API, changing provider addresses the contract and not the mechanism, since a tool argument carried private data outward with nothing inspecting it.
- 5
Bounding tool arguments by source
The tool channel does not accept the controls the earlier chapters used: a search query cannot be an enum or a resolved id the way a quarantined value can, and default-deny egress waves it through because the search API is an allowlisted destination. What does work is bounding the argument at its source — deriving recipients, destinations and webhook targets from your own configuration rather than from model output, restricting which part of the context a free-text argument may be composed from, and routing tool egress through a proxy that can see and log what the arguments carried.
- 6
Automatic fetch surfaces
The surfaces that transmit on the model's behalf go well beyond your renderer: link unfurling that fetches a target server-side to build a preview, image proxies, redirect followers, and tool side effects. Some are owned by a platform team or a vendor rather than by you. You will learn to build the list, say how each is tested and who owns it, and rank the three you can actually close on severity and ownership together.
- 7
Tracing a planted canary
Plant a unique string in a private record, run an indirect injection that attempts a rendered link, a tool call and an outbound webhook, and see which arrives. If only the webhook does, you have found one boundary that permits leakage and two blocks you cannot yet name. This chapter covers the evidence to collect at each hop and why distinguishing an enforced control from an incidental one is the point of the exercise.
External resources
- Imprompter: Tricking LLM Agents into Improper Tool Usearxiv.org
Imprompter demonstrates how tool-triggered Markdown image requests exfiltrate data from LLM agents.
- Advanced Data Exfiltration Techniques with ChatGPT · Embrace The Redembracethered.com
This is a substantive practitioner security write-up demonstrating how indirect prompt injection exfiltrates data through markdown image URLs, links, and plugin-generated tool parameters, with a concrete end-to-end payload and discussion of rendering and confirmation risks.
- ChatGPT Plugins: Data Exfiltration via Images & Cross Plugin Request Forgeryembracethered.com
The canonical writeup of markdown-image exfiltration, end to end
- LLM01: Prompt Injection | Data Exfiltration with Markdown | AI Security ExpertMartin Voelk
Live demo of leaking context through a rendered image URL
- SpAIware & More: Advanced Prompt Injection Exploits in LLM ApplicationsBlack Hat
Rehberger on links, tool params and persistent exfil channels