Lesson 2 of 6 · 6 min read
Data Exfiltration Channels in LLM Applications
In this lesson
TL;DR: Exfiltration is the last link of most prompt injection attacks: the model has private data in context and an instruction to send it somewhere. The channels include tools that send messages or make requests, URLs that carry data in their path or query string, markdown images that the client fetches automatically, links users are persuaded to click, link previews, and writes to places the attacker can read. Rendering and egress controls close these channels deterministically, which is why they are often the cheapest strong defence.
Before you read
Pick an answer before you read further. The lesson below explains it, and guessing first, right or wrong, helps the explanation stay with you.
1An assistant has no tools at all. It reads the user's documents and answers in a chat interface that renders markdown. Can an injected document make it leak data to an attacker?
Why channels matter more than injections
You cannot reliably stop a model from being instructed to leak. You can make leaking impossible. If every path out of the system goes only to destinations the attacker cannot read, an injected model holding private data has nowhere to send it. This is the "external communication" leg of the lethal trifecta, and it is often the easiest leg to remove or restrict.
The channels
Explicit tools. Email, chat messages, HTTP requests, webhooks, ticket comments, file uploads. Obvious, and usually what teams think of first.
URLs as carriers. Any request can carry data in its path, query string or headers. A "fetch this page" tool is an outbound channel, because the model chooses the URL.
Markdown and HTML rendering. An image tag makes the client request the image URL as soon as the message renders. Reference-style markdown, HTML in responses, CSS backgrounds and other auto-loaded resources are variants. Public research has demonstrated this against many production assistants since 2023.
Links. A link with data in its URL needs a click, which a well-crafted message can obtain ("click here to verify your account").
Previews and unfurling. Chat platforms and email clients often fetch URLs to build previews, turning a link into an automatic request.
Writes the attacker can read. Public pull requests, public comments, shared documents, calendar invites to external addresses, DNS lookups from code execution.
Assistant
Has private data
Send / HTTP tool
Explicit
Attacker's server
Also in the picture
Rendered image
- Fetched on display
Link or preview
- Click or unfurl
Public write
- Comment, PR, invite
Four kinds of exit
Only one of them is a tool the team designed as outbound. The rest come from rendering, clients and ordinary writes.
Controls
| Channel | Control |
|---|---|
| Send and HTTP tools | Egress allowlist through a proxy; recipient policies; confirmation for new destinations |
| URL fetch tools | Allowlist destinations, or forbid fetching URLs that did not come from the user; block private address ranges |
| Rendered images and resources | Render images only from allowlisted origins or through a proxy that strips query strings; CSP img-src and connect-src |
| Links | Show the full destination, require confirmation for external links, or strip links to unknown domains |
| Previews | Disable automatic unfurling of AI-generated content |
| Public writes | Treat them as egress: policies on what an agent may publish, review for public repositories |
Two cautions. An allowlisted domain that redirects or proxies to arbitrary URLs makes the allowlist meaningless; audit allowed origins. And markdown has more than one way to embed an image; sanitise the rendered HTML, not just one markdown syntax.
How vendors closed the URL channel, and what is left
URL-based exfiltration has a published engineering history worth knowing:
- Domain allowlists were not enough. OpenAI's write-up on preventing URL-based exfiltration in agents describes starting with a hand-curated list of allowed domains. It covered only about 10% of the URLs users actually visited, so users were pushed through warnings constantly, and open redirects on allowed domains bypassed it anyway.
- An index-based allowlist replaced it. OpenAI moved to allowing only URLs its search crawler had already seen independently, which therefore cannot contain a particular user's data, with canonicalisation of URLs before comparison; URLs the user typed or that came back from search are also treated as safe. Expected coverage rose above 80% of visited URLs. The guarantee is deliberately narrow: loading such a resource cannot carry user data out; it says nothing about whether the content is safe.
- No arbitrary URL construction. OpenAI's deep research system card (February 2025) states that the agent may not navigate to or construct arbitrary URLs, which stops it putting an API key into URL parameters, and reports injection evaluations falling from about 4% to 0% after mitigation.
- Deterministic blocking. Microsoft's security response team wrote in July 2025 that it deterministically blocks the impact of known exfiltration methods, including Markdown image injection and certain untrusted links, and that Outlook's Copilot requires the user to send drafted mail themselves.
- Turning rendering off. After CamoLeak, GitHub disabled image rendering in Copilot Chat.
What remains is slow and noisy. With an index-based allowlist, an attacker needs per-character URLs that were already crawled, so leaking even a street address takes a dozen sequential requests to one domain, which shows up in logs as a burst.
Worked example: exfiltration bandwidth per channel
| Channel design | What one injected response can send | Detectability |
|---|---|---|
| Unrestricted image rendering | A whole API key or email thread in one URL's query string, roughly 2,000 characters, silently | Low: one ordinary-looking fetch |
| Domain allowlist with an open redirect on an allowed domain | The same: the allowlist is moot | Low |
| Index-based allowlist (only pre-crawled URLs) | One character per request: 13 requests for "123 Main Street", about 40 for a 40-character key | High: correlated bursts to one domain |
| Rendering disabled | Nothing through images; remaining channels are tools and user clicks | Not applicable |
Each control converts "one silent request" into "many correlated requests" or none. Pair it with a cap on outbound fetches per response and alerts on bursts.
Domain allowlist
Model emits image URL
Allowed domain redirects
open redirect
Whole secret in one request
Outcome, unsafe: One silent fetch leaks it all
The allowlist trusted a domain, not a URL.
Index-based URL allowlist
Model emits image URL
URL never seen by the crawler
cannot contain user data
Fetch refused
Outcome, safe: Only pre-existing URLs load
Residual: slow per-character bursts, which are visible.
Trusting domains
Any redirector or proxy on an allowed domain carries the data onward.
A channel that needs no injection
Weiss and colleagues (2024) showed that streamed responses leak information to a network observer even over TLS: because many assistants sent one token per encrypted packet, packet sizes revealed token lengths, and from those the researchers reconstructed 29% of responses accurately and inferred the topic of 55%. The fix is padding or batching tokens before sending. It is a reminder that "exfiltration" includes side channels an attacker on the user's network can read without touching the model.
Misconceptions interviewers listen for
- "A text-only assistant cannot leak data." Rendered Markdown images and links are network requests.
- "Our CSP's img-src fixes it." First-party proxies and redirectors on the allowlist carry data onward.
- "Domain allowlists are enough." Open redirects defeat them, and low coverage trains users to click through warnings.
- "Block the injection and the leak is solved." Detection misses; block the channel.
What if · interview follow-ups
Hold your answer as the constraints change
You are reviewing an AI assistant that reads a user's documents and email, renders Markdown answers in a web app and can browse the web. The interviewer asks how data could leave, one channel at a time.
Start here
What if the assistant can only reply with text?
What happens when the app renders that text?
Rendered Markdown can include images and links; an image loads automatically and its URL can carry data in the query string, so a text-only reply can leak silently. Disable model-emitted images or restrict them to an allowlist of specific URLs, and show link destinations before navigation.
Carry it forwardRendering turns text into network requests; treat rendered output as an egress channel.
Weak answerDeclaring the assistant safe because it has no tools.
Constraint changes
What if images are allowed only from five trusted domains?
Do any of those domains redirect or proxy?
Audit each for open redirects and image proxies: either forwards the data to an attacker-chosen destination, which is why OpenAI abandoned domain allowlists and why EchoLeak and CamoLeak worked. Move to URL-level allowlists or disable model-driven images.
Carry it forwardAn allowlist entry trusts everything that host will fetch or redirect to.
Weak answerAssuming first-party or reputable domains are safe destinations.
Constraint changes
What if you adopt an index-based allowlist; what is left?
Can an attacker pre-place URLs in the index?
An attacker who gets per-character URLs crawled in advance can leak slowly, one request per character. Cap outbound fetches per response, alert on bursts of requests to one domain, and keep secrets out of contexts where external content is present.
Carry it forwardGood controls turn silent single-shot leaks into slow, detectable ones; finish with rate limits and alerts.
Weak answerClaiming the index-based approach closes exfiltration completely.
Constraint changes
What if the assistant cannot send email but can open public pull requests?
Is publishing outward a channel?
Yes: any action that writes somewhere others can read, such as public issues, comments, documents shared by link or calendar invites to external guests, is an egress channel. Apply the same rules: approval for outbound-visible writes when untrusted content is in context, and recipient or destination restrictions.
Carry it forwardCount every outward-visible write as egress, not only network fetches.
Weak answerListing only HTTP requests as exfiltration paths.
Constraint changes
What if an attacker on the user's Wi-Fi watches the encrypted stream?
What do packet sizes reveal when tokens are sent one at a time?
Token lengths, from which a published attack reconstructed many responses and inferred topics. Pad or batch tokens in streamed responses so packet sizes do not track tokens. This needs no injection at all, so it belongs in the transport design.
Carry it forwardSide channels on encrypted streams are exfiltration too; design the stream format against them.
Weak answerAssuming TLS hides everything about the response.
Now defend it
As the defender, what would you monitor to catch exfiltration attempts?
Outbound fetches triggered by model output, per response and per session, with alerts on bursts to one domain; URLs in model output pointing outside expected destinations; requests through allowlisted proxies and redirectors; outward-visible writes such as public posts or external invites when untrusted content was in context; and injection-classifier hits correlated with any of these.
How this shows up in interviews
"How can an assistant that only outputs text still leak data?" is a favourite, because many candidates think only of tools. Name the rendering channel first, then the others, and propose deterministic controls in the client and at the network edge. Connect it to detection: log outbound URLs from assistant responses and alert on high-entropy query strings or first-seen domains.
Say it in 30 seconds: "An injected model still needs a way out, and LLM apps have many: send and HTTP tools, URLs that carry data, markdown images that clients load automatically, links and previews, and public writes. I close them deterministically: egress allowlists through a proxy, a renderer that only loads images from allowed origins with a strict CSP, no auto-unfurling, and policies on public writes. That works however the injection was phrased."
Check yourself
Say or write your answer first, then reveal. Explaining it from memory, in your own words, is the skill an interviewer is checking.
1Your CSP allows images only from your own CDN domain. Under what condition can data still leave through an image?
2Why did OpenAI move from a domain allowlist to an index-based URL allowlist for agents?
3How can a streamed answer leak to a network observer even over TLS?