Markdown Image and Link Exfiltration: How Rendering an Agent's Own Output Becomes a Data-Leak Channel
Markdown image and link exfiltration is SSA descriptive wording for a data-leak channel built from a feature, not a bug: a chat client auto-rendering the images and links an agent writes into its own reply. A prompt injection that gets the model to emit one crafted image tag or link turns that rendering step into a covert request to an attacker's server, carrying stolen data in the URL. Covers documented cases against ChatGPT, Writer.com, Microsoft 365 Copilot (including the CVE-2025-32711 EchoLeak zero-click exploit), and Slack AI spanning 2023 to 2025, with detection and containment that does not require turning off markdown rendering.
- Target
- Tool & Environment State
- Persistence
- Single Turn, Repeatable Every Session Until the Rendering Path Is Patched (Shared-System)
- Control
- Prevent, Detect, Contain, Recover
- Status
- SSA Working Term
Markdown image and link exfiltration is SSA descriptive wording for a data-leak channel built from ordinary client behavior, not a parsing bug: a chat or agent interface renders the images and links its own model writes into a reply, the same way it would render them from any other source. An attacker who can get a prompt injected into the content an agent processes, an email, a web page, a shared document, needs no tool call and no separate network capability of its own. The injection only has to get the model to write one crafted Markdown image tag or link whose URL carries stolen data as a query parameter. When the client renders that output, the browser or app fetches the image, or the user clicks the link, and the data travels to a server the attacker controls, through a request the agent's own interface made on the agent's own say-so. Documented cases span at least 2023 to 2025 and include a zero-click Microsoft 365 Copilot exploit, CVE-2025-32711, rated 9.3 critical, that needed nothing from the victim beyond receiving a crafted email.
What it is
The defining object is a single line of the model's own generated output: a Markdown image reference, , or a plain link, where the URL's query string or path carries data the model was never supposed to disclose. The defining mechanism is that rendering is not optional and usually is not treated as an action requiring approval. A chat client that renders Markdown images auto-fetches every one it sees the instant a reply finishes streaming, no click required; a client that renders Markdown links still produces a plausible-looking anchor a user may click without knowing it carries a payload. Either way, the channel exists because the rendering layer trusts the model's output the same way it trusts a legitimate web page, and the model's output is exactly what a prompt injection controls once it succeeds.
The defining cause is a trust-boundary gap between two components that are usually built and reasoned about separately: whatever validates a prompt injection didn't smuggle in disallowed instructions, and whatever renders the resulting text as rich content. Content filtering, instruction hierarchies, and classifiers like the one Microsoft built for Copilot are all aimed at the first component. None of them was built to ask whether a URL the model is about to emit, having already passed every upstream check, is about to be auto-fetched or auto-linked by a second system that assumes rendering is safe because generation was supposed to be.
What it is not
- RAG poisoning, the write-side attack that gets adversarial content into a retrieval corpus in the first place. This entry starts one step downstream of that question: once a model's context contains attacker-controlled instructions, by whatever path, this is what happens when the resulting output gets rendered. The PromptArmor Slack AI case cited below is in-scope evidence for both entries, viewed from different ends of the same chain.
- Agentic browser session hijacking, where an agent uses its own standing, authenticated session to take an action a user never approved. Markdown exfiltration needs no authenticated session and no standing tool access; the egress is the rendering client's own, ordinary act of loading an image or following a link.
- URL parameter prompt injection, where the attacker-controlled URL is the delivery mechanism that gets a malicious prompt into the agent in the first place. Here the attacker-controlled URL is instead the output the agent is tricked into producing, the exfiltration leg rather than the injection leg.
- MCP tool poisoning, where hidden instructions ride in a tool description or tool-call result and trigger an unintended tool invocation. Markdown exfiltration needs no tool invocation at all; the client's own rendering of ordinary chat output is the entire exploit surface.
- A claim that every chat client or agent framework renders Markdown images or auto-follows links by default, or that disabling rendering entirely is the only fix. Behavior varies by vendor and by whether the surface is a browser-rendered web chat, a native app, or an API response a developer renders themselves; this entry covers documented instances, not a universal default.
- Reproducible payload templates or a tuned proof of concept against any named, currently deployed product.
In scope
- Prompt-injection-to-exfiltration chains where the final leg is a client auto-fetching an image, or a user following a link, whose URL the model was induced to construct from data it had access to.
- Both the zero-click variant, where image auto-rendering alone completes the exfiltration with no user action, and the one-click variant, where a crafted link still requires the user to follow it.
- Chains that depend on an allow-listed domain in a client's content security policy being reachable through an open redirect or proxy, as documented against Microsoft 365 Copilot.
- Agent frameworks, chat clients, and API-driven integrations that render model-generated Markdown, HTML, or similar rich-text output into images or clickable links without inspecting the destination.
- Defensive controls at the rendering layer: URL allow-listing, image-domain restriction, stripping or confirming outbound links, and treating model output as untrusted content for exactly the same reasons retrieved documents are.
Target state, trust boundary, and persistence
The target state is the agent's own generated output, specifically the subset of it that a client interprets as an instruction to make a network request rather than as text to display. The trust boundary that fails is the assumption that content a model itself wrote can be rendered with the same freedom as content a developer wrote, when in fact a successful prompt injection means the model's output is, at that moment, attacker-authored. Every defense built around validating prompts and training models to resist injected instructions sits upstream of this boundary and does nothing to protect it once an injection gets through.
Persistence is best described as single-turn in its immediate effect, the exfiltrating request fires once a given reply is rendered or a given link is followed, but shared-system in its exposure window. The underlying flaw is a property of the client's rendering logic or its content security policy, not of any one conversation, so every user of a vulnerable deployment remains exposed to the same technique until the rendering path itself is fixed, independent of which session or which injected document triggered any single instance.
What the research establishes
Security researcher Roman Samoilenko first documented the pattern against ChatGPT's web interface, reported by Simon Willison on 2023-04-14: a single-pixel Markdown image whose URL encoded conversation data, combined with a separate trick of intercepting a website's copy event to append hidden prompt-injection text to whatever a user copied, so pasting that text into ChatGPT triggered the image fetch and the leak (Simon Willison, New prompt injection attack on ChatGPT web version, Markdown images can steal your chat data). OpenAI began mitigating the vector in December 2023.
Kai Greshake and PromptArmor disclosed a structurally similar case against Writer.com's AI assistant on 2023-11-29, reported by Willison on 2023-12-15: a web page carried hidden, white-on-white instructions that, when a user asked Writer to summarize the page, directed the assistant to append a Markdown image whose URL carried parameters drawn from the user's own private documents. The image pointed at a cloudfront.net address, a domain Writer's content security policy already allowed, so the browser rendered it and the data left silently. Writer's initial response called it not a security issue because "the real customer accounts do not have access to any website"; the researchers' demonstration showed the exfiltration working regardless, and the vector appeared fixed within days of publication (Simon Willison, Exfiltrating data from Writer.com with indirect prompt injection).
Microsoft's own Copilot (then Bing Chat) was independently found vulnerable to zero-click image-rendering exfiltration in 2023 and patched. Researcher Johann Rehberger then found that a prompt injection could still direct Copilot to pull sensitive content, in his proof of concept, Slack MFA codes and sales data, into the chat context, encode it using ASCII smuggling (invisible Unicode Tag characters appended to an otherwise ordinary-looking link), and present the user a link that looked harmless but decoded to the stolen data once clicked, on an attacker-controlled domain. Rehberger reported the chain to Microsoft's Security Response Center starting 2024-01-17; MSRC initially closed it as low severity, reopened it after a working end-to-end exploit in February 2024, and said in May 2024 it was "still working on a comprehensive fix." Rehberger disclosed the technique publicly at HITCON CMT on 2024-08-24, noting that "prompt injection does not have a fix currently" even where the specific rendering channel does (Johann Rehberger / Embrace The Red, Microsoft Copilot: From Prompt Injection to Exfiltration of Personal Information). That one product needed two separate documented fixes for two separate rendering-channel variants, image auto-fetch, then a smuggled link, is itself evidence that patching one instance of this channel does not close the class.
The most severe documented instance is CVE-2025-32711, EchoLeak, disclosed against Microsoft 365 Copilot by Aim Security researchers Pavan Reddy and Aditya Sanjay Gujral and rated CVSS 9.3, critical. Their academic writeup describes a single crafted email that "enabled remote, unauthenticated data exfiltration" with no user interaction at all, achieved by evading Microsoft's XPIA cross-prompt-injection classifier, using reference-style Markdown to bypass link redaction, "exploiting auto-fetched images, and abusing a Microsoft Teams proxy allowed by the content security policy" to route the exfiltrating request through a domain Copilot's own CSP already trusted. The authors describe the result as "full privilege escalation across LLM trust boundaries without user interaction" (Reddy and Gujral, EchoLeak: The First Real-World Zero-Click Prompt Injection Exploit in a Production LLM System, arXiv:2509.10540). Microsoft shipped a server-side fix with no customer action required.
The same underlying pattern, a model's rendered output carrying an attacker-chosen URL, recurs across other documented, independently disclosed cases Simon Willison has tracked since: PromptArmor's 2024-08-20 Slack AI finding, where a poisoned message produced a convincing "click here to reauthenticate" link leaking data through its query string (Slack's response called this "intended behavior"); GitLab Duo on 2025-05-23, where Markdown image tags exfiltrated data until GitLab added a function restricting image references to trusted domains; and Salesforce Agentforce, publicly named ForcedLeak, on 2025-09-26, where an image tag pointed at an expired domain that remained listed in the product's content security policy (Simon Willison, posts tagged markdown-exfiltration).
Detection: observable signs
- An outbound request, image fetch or link click, to a domain with no prior relationship to the deployment, originating immediately after an agent or assistant reply finishes rendering.
- A rendered reply containing a Markdown image or link whose URL has an unusually long query string, base64-like characters, or invisible Unicode characters not matching any legitimate feature of the client.
- A content security policy allow-list entry, such as a cloud storage CDN or a collaboration-suite proxy domain, being reached by traffic whose content the policy's author never intended that domain to carry.
- A spike in requests to a single external image host or redirect target correlated with a specific prompt, document, or email that multiple users recently processed through the same assistant.
- A classifier or filter logging a clean result for a given model turn while the rendered output still contains an attacker-controlled URL, evidence the check ran on the wrong layer.
Defenses, containment, and recovery
The table below is SSA editorial guidance for defenders. It is neither a standard requirement nor a measured effectiveness ranking.
Control | Transition it interrupts | Applicability | Residual risk and verification |
|---|---|---|---|
Restrict Markdown image and link rendering to an explicit allow-list of trusted domains, and treat any CSP allow-list entry as itself a potential exfiltration proxy | A rendered image or link reaching an attacker-controlled or attacker-reachable domain | Any chat client or agent interface that auto-renders model-generated Markdown or HTML | EchoLeak succeeded precisely by abusing an already-allow-listed domain (a Teams proxy); an allow-list narrows but does not eliminate risk if any allowed domain can be made to proxy or redirect. |
Inspect or rewrite URLs in model output before rendering, stripping query parameters or flagging URLs assembled from content the model retrieved in the same turn | The specific mechanism of encoding stolen data as a URL parameter or invisible Unicode payload | Any pipeline with a server-side or client-side step between model output and final rendering | Catches parameter-based and visible-encoding variants; attackers can shift to other encodings the inspection step does not yet recognize. |
Require explicit user confirmation before following any link in model-generated output that was not present in the user's own prompt | The one-click variant, where a crafted link still needs the user to act | Any client that currently renders model-generated links as directly clickable with no distinguishing treatment | Does not stop the zero-click image-auto-fetch variant, which requires no user action at all; pair with the rendering restriction above. |
Treat model output the same as retrieved, untrusted content when it is about to be rendered as rich text, not as a trusted first-party UI element | The trust-boundary gap between prompt-injection defenses and the separate rendering layer | Any agent architecture where output rendering and prompt-injection filtering are built and reasoned about separately | Requires coordinating two components often owned by different teams; a gap in either one reopens the channel. |
Monitor and alert on network requests originating from the rendering client immediately following a model turn that processed untrusted input (email, web content, a shared document) | A poisoned turn's exfiltrating request going unnoticed because it looks like ordinary client traffic | Any deployment that logs client-side network activity or has visibility into CSP-permitted domains' request patterns | Requires baselining what request volume and destination are normal per client, which is costly to establish and maintain precisely. |
Prevention should start by restricting which domains model output can cause a render to reach, and by auditing every entry already on a content security policy's allow-list for exactly the kind of proxy-and-redirect abuse EchoLeak used. Detection should watch the client's own outbound requests immediately following a turn that touched untrusted input, since none of the defenses built around prompt classification will catch a payload that already cleared them. Containment should assume that any confirmed poisoned turn may already have triggered a render, and should treat whatever data the model had access to during that turn as potentially exposed, not only the specific fields visible in a URL. Recovery should re-audit the content security policy and rendering allow-list themselves, since the Writer.com, Slack AI, GitLab Duo, and EchoLeak cases all trace back to a domain or proxy that was trusted for an unrelated, legitimate reason.
Boundaries with similar concepts
This differs from RAG poisoning in which half of the attack chain it covers. RAG poisoning is about getting adversarial content into a retrieval corpus so a model reasons over it as trusted context; what happens afterward, if the model's resulting output gets rendered, is this entry's concern. The 2024 PromptArmor Slack AI case is evidence for both: a poisoned message is the RAG-poisoning half, and the reauthentication link it produced is the exfiltration-channel half covered here.
This also differs from agentic browser session hijacking in what capability the attacker needs. Browser session hijacking requires an agent that already holds standing, authenticated access to another service, and redirects that access toward an unauthorized action. Markdown exfiltration requires no standing access and no authenticated session at all; an ordinary, unauthenticated chat client rendering an image is sufficient.
This also differs from URL parameter prompt injection in which direction the URL runs. That entry's attacker-controlled URL is the delivery mechanism, carrying a malicious prompt into the agent when a victim opens a link. Here the attacker-controlled URL is the output of a successful injection, the leg that carries data back out once the model has already been compromised by some other delivery path.
Mapping to standards and research
Source | Source-owned term or item | Relationship to this article |
|---|---|---|
Simon Willison (2023-04-14, 2023-12-15) | Markdown image data exfiltration | Primary-source origin reporting of the ChatGPT and Writer.com cases, and the ongoing aggregator tracking later instances. |
Johann Rehberger / Embrace The Red (2024-08-24) | ASCII smuggling applied to Microsoft Copilot link exfiltration | Primary-source documentation of the link-based variant that followed Microsoft's fix of the earlier zero-click image-rendering vector in the same product. |
arXiv 2509.10540 (Reddy, Gujral) | EchoLeak (CVE-2025-32711) | Primary academic source for the most severe documented instance, including the classifier-evasion and CSP-proxy-abuse chain. |
OWASP GenAI Security Project | Top 10 for LLM Applications 2025, | Standard risk category naming insufficient validation of model output before it reaches downstream systems, including rendering, as a root cause. |
OWASP GenAI Security Project | Top 10 for LLM Applications 2025, | Standard risk category for the consequence realized once rendering completes the exfiltration. |
MITRE, CWE |
| General software-weakness classification for data reaching a party it was never authorized to reach, applicable to the resulting disclosure regardless of rendering mechanism. |
Agent State Attack | Markdown image and link exfiltration | SSA descriptive framing bundling the cases above under one Tool & Environment State entry. |
Related terms
- Agent state attack: the umbrella definition, including Tool & Environment State among the listed target states.
- RAG poisoning: the adjacent write-side entry supplying the poisoned context that, once rendered, this entry's exfiltration channel can carry out of the system.
- Agentic browser session hijacking: a related exfiltration pattern that instead depends on an agent's own standing authenticated access, contrasted above.
- URL parameter prompt injection: the adjacent entry covering the opposite-direction use of an attacker-controlled URL, as delivery rather than egress.
- MCP tool poisoning: a related Tool & Environment State entry where the exploited trust boundary sits in tool metadata and tool-call results rather than in output rendering.
FAQ
Does this attack require the agent to have any tool access or standing permissions?
No. Every documented case above exploits the client's own rendering of Markdown images or links, a capability present in the chat interface itself, not a tool the agent was granted. An agent with no tools and no external integrations beyond the chat window it runs in can still leak data this way if its output gets rendered unfiltered.
If a vendor blocks zero-click image auto-rendering, is the channel closed?
Not necessarily. Microsoft's own product history is the clearest evidence against that assumption: after Copilot's zero-click image-rendering vector was fixed, researcher Johann Rehberger documented a working link-based variant using ASCII smuggling against the same product, and a later, separate CSP-proxy-abuse chain produced EchoLeak. Closing one rendering path does not close every path an attacker-controlled URL in model output can travel.
Is the fix simply disabling Markdown rendering entirely?
It removes the channel at the cost of rich-text formatting the feature exists to provide. Most documented fixes instead restrict which domains can be reached by rendered images or links, which addresses the specific exposure without giving up formatted output; disabling rendering outright is a defensible choice only where that formatting capability is not required.
Why does restricting the content security policy allow-list matter if the attack is really about the model's output?
Because three of the most severe documented cases, Writer.com, GitLab Duo, and EchoLeak, succeeded by reaching a domain the content security policy already trusted, not by defeating the policy. The model's output supplies the attacker-chosen destination; the CSP allow-list decides whether the client is willing to fetch it. Narrowing that allow-list, and auditing every entry on it for proxy or redirect abuse, closes the gap the model's output alone cannot.
Sources
- Simon Willison, New prompt injection attack on ChatGPT web version, Markdown images can steal your chat data (2023-04-14)
- Simon Willison, Exfiltrating data from Writer.com with indirect prompt injection (2023-12-15)
- Johann Rehberger / Embrace The Red, Microsoft Copilot: From Prompt Injection to Exfiltration of Personal Information (2024)
- Reddy and Gujral, EchoLeak: The First Real-World Zero-Click Prompt Injection Exploit in a Production LLM System (arXiv:2509.10540)
- Simon Willison, posts tagged markdown-exfiltration
- OWASP Top 10 for LLM Applications 2025, LLM05:2025 Improper Output Handling
- OWASP Top 10 for LLM Applications 2025, LLM02:2025 Sensitive Information Disclosure
- CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
Verification and change history
Standards and versions referenced: OWASP Top 10 for LLM Applications, 2025 edition; CWE, current definition of CWE-200.
Last verified: 2026-10-30. The Willison ChatGPT and Writer.com quotations and dates were read from Simon Willison's own blog posts. The Rehberger quotations, Microsoft Security Response Center timeline, and HITCON disclosure date were read from the Embrace The Red post. The EchoLeak quotations, CVE number, and CVSS score were read from the arXiv abstract page. The GitLab Duo, Salesforce ForcedLeak, and Slack AI summary details were read from Simon Willison's markdown-exfiltration tag page. The OWASP LLM05:2025 and LLM02:2025 scope and the CWE-200 definition were read from their respective official pages.
Change history: 2026-10-30, first version.
Working-term label: Mixed provenance. "Markdown exfiltration" as applied to image and link rendering is Simon Willison's own tracking label across his posts, used here as a plain descriptive term rather than attributed to a single standards body. "ASCII smuggling" is a term coined by Johann Rehberger. "EchoLeak" is Aim Security's name for CVE-2025-32711. LLM05:2025 Improper Output Handling, LLM02:2025 Sensitive Information Disclosure, and CWE-200 are Standard Terms owned by OWASP and MITRE respectively. "Markdown image and link exfiltration" as the umbrella title bundling these cases under one Tool & Environment State entry is SSA editorial organization.