Threat · curated 15 Jul 2026

Data Exfiltration via Markdown Images: The Quiet AI Vulnerability

Dossier

Coverage timeline

25 Apr 2026wraith.sh

Single-source incident — first reported, latest, and curated coincide.

Why it matters

Markdown image exfiltration is a zero-click, invisible channel that leaks sensitive AI context to attacker servers and sits at the seam between LLM behavior and frontend rendering where most security reviews fail to probe.

Wraith's attack guide by Anthony D'Onofrio details data exfiltration via markdown image rendering in AI products, where an injected payload (via prompt injection, RAG doc, shared document, or email) causes an LLM to emit a markdown image whose URL embeds secrets like system prompts, conversation history, or API keys; when the chat client renders the markdown, the browser silently fetches the attacker's URL, leaking the data with zero clicks and no visible artifact. The guide notes variants have hit ChatGPT, Microsoft Copilot, GitHub Copilot Chat, Slack AI Assistant, Google Bard, and Claude.ai, and covers four defensive patterns.

guidance

Summary

This is a reference attack guide for markdown image data exfiltration, an AI-product vulnerability class in which attacker-controlled text reaches a model's context and causes the model to emit a markdown image (or equivalent auto-fetching HTML element) with sensitive data embedded in the URL; when the chat UI renders it, the client silently issues an HTTP request to the attacker's server, delivering the data into their access log with zero user interaction.[0]

The guide stresses that the channel is disproportionately dangerous because there is no visible artifact for the user, it crosses a trust boundary using the web's default image-fetch behavior, and it needs no plugin, tool, or code execution — the render is the attack. Anything the agent can read in context (system prompt secrets, conversation PII, tool/RAG output, and even cross-tenant data in shared multi-tenant instances) is exfiltrable if the channel is open.[0]

The article documents that variants have affected ChatGPT, Microsoft Copilot, GitHub Copilot Chat, Slack AI, Google Bard, and Anthropic Claude.ai, and that in each case the durable fix lived at the rendering layer rather than the model layer. It recommends four layered defenses — a server-side image proxy with allowlist, a strict CSP img-src allowlist, markdown sanitization at render time, and disabling agent-controlled HTML/markdown rendering entirely — supplemented by output-level filtering.[0]

Attack chain

  1. Access: The agent has read access to data worth stealing — system prompt secrets, conversation history/PII, or tool output such as RAG chunks, file contents, calendar entries, or internal API responses.[0]
  2. Inject: Attacker-controlled text reaches the model's context via direct injection (attacker is the user), indirect injection (a webpage, email, RAG index row, ticket comment, PDF, calendar invite, or Slack message the agent processes), or tool feedback loops.[0]
  3. Emit: The model complies with the injection and outputs a markdown image (or HTML img/CSS/other auto-fetching element) with the sensitive data hidden in the URL, often base64- or URL-encoded to evade naive filters.[0]
  4. Render: The chat UI renders the markdown as an HTML img tag, whose default behavior is to issue a GET request to the src URL unless the UI explicitly intervenes.[0]
  5. Leak: The browser (or a platform's server-side unfurl fetcher) sends the request to the attacker's server, whose access log captures the URL and its query string — completing exfiltration with no user click.[0]

How it works

The vulnerability arises at the seam between LLM output behavior and frontend rendering. Most markdown renderers translate the syntax for an image into an HTML img element, and an img element's default behavior is to issue a GET request to its src URL on render. When the model has been induced to place sensitive context data into that URL's query string, path, or fragment, the automatic fetch transmits the data to whatever host the URL points at.[0]

Model-layer defenses are insufficient because models trained against direct prompt injection still emit markdown images on request, especially when wrapped in plausible framing (e.g. rendering a small 'thank-you' image to confirm receipt), and encoding decorations such as base64 or URL-encoding do not meaningfully change compliance. The reliable control point is the rendering boundary that decides where images may load from.[0]

The attack class extends beyond markdown image syntax to any rendered element that auto-fetches: inline HTML img tags, picture/source elements, CSS background-image in style attributes, meta refresh and link prefetch redirects, hyperlink auto-preview/unfurl (which fetches server-side during Open Graph/favicon retrieval), and iframe/video elements. A defense that only blocks the markdown image syntax leaves most of the surface open.[0]

Affected versions and patch status

ProductAffectedPatch status
ChatGPT (plugins)Markdown image exfil via plugins demonstrated April 2023 by Roman Samoilenko; class re-emerged with new plugin/browser-tool capabilitiesOpenAI shipped CSP-based mitigations soon after disclosure[0]
Microsoft Copilot for Microsoft 365End-to-end exfil chains via email and document integrations (2024)Microsoft shipped server-side image proxying and filter changes[0]
GitHub Copilot ChatMarkdown image exfil from chat context including code surfaces (2024)Patched via image-host allowlisting[0]
Anthropic Claude.aiMultiple variants involving the artifact rendering surface and projects retrieval surface (2024–2025)Defense centered on a server-side image proxy[0]
Slack AICross-channel exfiltration via poisoned message leaking data through link unfurl + image preview (2024), demonstrated by PromptArmorSalesforce/Slack shipped fixes[0]
Google BardListed among products where a variant of the attack has occurredShipped a fix or mitigation per the guide[0]

Key takeaways

  • The load-bearing failure is the frontend rendering an image without preflight or allowlist, not the LLM emitting markdown; every durable vendor fix landed at the rendering layer, so defenders should treat model-output filtering as friction only.[0]
  • Assume every byte the agent can read in context is exfiltrable if the channel is open; the blast radius (system prompt secrets, conversation PII, tool/RAG output, cross-tenant data) depends only on what the agent can access.[0]
  • A defense that only blocks markdown image syntax patches roughly a third of the surface; testing and controls must cover HTML img, CSS background-image, meta/link redirects, hyperlink unfurls, iframe, and video.[0]
  • If you ship an AI product that emits markdown to users and lack an image proxy with an allowlist, you have this vulnerability — the only variable is attacker effort, not whether the channel exists.[0]

Defensive actions

  • Deploy a server-side image proxy with a host allowlist that rewrites every image URL in agent output to your own proxy, validates it against the allowlist, and strips query strings and fragments on outbound requests.: This is the pattern most production AI products converge to and closes the channel at the rendering layer; a proxy that fetches arbitrary hosts is the same channel with extra steps, so the protection comes from the allowlist and URL canonicalization.[0]
  • Set a strict Content Security Policy img-src allowlist (e.g. img-src 'self' once images are proxied through your own host).: The browser then refuses to fetch images from any non-permitted host, providing defense in depth; CSP is redundant to the proxy but fails silently when misconfigured, so it should not be the sole control.[0]
  • Sanitize markdown at the rendering layer using a maintained library with an image-URL validation hook, rejecting cross-origin hosts, URLs with query strings, data URIs, URL fragments, IDN homograph hosts, IP addresses, and file URLs.: When a proxy cannot be deployed, render-time sanitization is the next-best compensating control, though the bypass research is old and the surface is wide, so it should sit behind the proxy/CSP rather than serve as primary defense.[0]
  • Disable rendering of agent-controlled HTML and markdown entirely (plain text or a markdown subset excluding images and links) for high-risk surfaces.: The cheapest and most robust defense for multi-tenant products, sensitive tool surfaces, or agents processing external content; earn back each rendering capability with explicit controls.[0]
  • Add output-level filtering that regexes agent output before rendering to flag/strip image URLs whose parameters contain system-prompt, PII, or tool-output strings, with awareness of common encodings (base64, URL-encoding, hex), plus system-prompt provenance hints restricting image hosts.: These are supplementary controls that add friction and catch obvious cases and benign mis-emissions, but they are not a substitute for the structural rendering-layer defenses.[0]
  • Test every surface where agent output renders (chat UI, summary panels, email digests, exported reports, Slack/Teams/calendar) with each element variant using unique logged URLs, then repeat with indirect injection and, where applicable, cross-tenant data.: Each surface is a separate target — the chat UI may be patched while the email digest is not — and only watching an attacker-controlled access log reveals which channels are actually open.[0]