PromptFu
03 Offense: Agentic3.2Core18 min

Exfiltration channels

Markdown image rendering first: it carries OWASP's own worked scenario and the EchoLeak case.

LLM02:2026The exit, against five controls

Module 3.1 got an instruction in. This one gets data out, and it does it without a single tool that looks like “send”. That is why teams count the exit leg of the lethal trifecta as absent when it is present.

The workhorse: markdown image rendering

Most real exfiltration runs through a rendering feature rather than a tool. OWASP's Scenario #2 is the canonical shape:

The model inserts a markdown image whose URL exfiltrates the private conversation to an attacker-controlled domain. The user sees only the rendered image, never the instruction.
OWASP LLM01:2026 · Scenario #2

Three properties make it the default choice.

PropertyWhy it matters to the attacker
It is not a tool callNothing appears in the tool log. Reviews that enumerate tools and check their permissions miss it entirely.
The victim makes the requestTheir browser, their network position, their session. Outbound traffic carries no attacker fingerprint.
The payload is not in the proseIt rides in the URL. An output filter reading the reply for sensitive strings finds a sentence and a broken image.

Run it against five controls

Two of the five options below fail. They are not strawmen: they are the two controls a major vendor actually had deployed when this attack was demonstrated against their product.

The exit: getting data out

0 / 5

Signed in as Alice Okafor, tenant "acme". The target document belongs to tenant "globex".

Objective

Move the contents of a confidential document from inside the application to a host the attacker controls, using no tool that looks like 'send'.

Which control is deployed?

Step through the trace. Every node is a real place content enters or leaves the application, and each one arrives with the analysis beside it: what a defender can still do at that instant.

Synthetic world, no network requests: the exfiltration step decodes and displays the payload that would have left. Chain per OWASP LLM01 Scenario #2; the two failing controls are the pair EchoLeak defeated in Scenario #7.

The channel inventory

Anything that makes the client fetch a remote resource is an exit. The list is longer than most threat models allow for.

ChannelHow the bytes leave
Markdown imageData in the query string of an <img> the client resolves automatically.
Markdown link with auto-unfurlThe chat platform fetches the URL to build a preview card. Nobody clicked anything.
Reference-style markdownDefinition and use are split across the message, so a filter matching inline URLs sees neither half.
Invisible Unicode in a URLTag-block characters carry data a human reviewer cannot see. Module 2.4 has the ranges.
DNS lookupsData encoded in a subdomain. Resolution alone delivers it, with no HTTP request to inspect.
A tool that fetches by designfetchUrl, webhooks, an outbound API call with a free-text field. Module 1.7 calls these open-ended tools.
The first four require no tool at all. They are properties of the interface.

Bounds blast radius· survives adaptive attack

The controls that end this chain remove a capability rather than recognise an attack. A renderer that never resolves model-authored URLs, and an egress allowlist, both work without knowing what the payload looks like. Everything that has to identify the attack first has a published bypass.
Deep diveWhy filtering the URL is the wrong layer3 min

Link redaction has an enumeration problem identical to the one in module 2.4. To filter a URL you must first agree on what a URL looks like, and a renderer will accept many things a filter does not recognise: reference definitions, percent-encoding, split payloads assembled across turns, protocol-relative forms, and anything the markdown implementation happens to be liberal about.

The attacker only has to find one shape the renderer accepts and the filter does not. The defender has to find all of them. That asymmetry is why the control belongs at the fetch, where there is exactly one question to answer, rather than at the text, where there are unlimited ones.

Counting the exit leg honestly

Module 1.4 warned that “we have no external communication” is the most commonly wrong statement in the Rule of Two exercise. This is why.

Ask these about the interface, not the tool list
Does the client render markdown images?          → exit exists
Does it unfurl link previews?                    → exit exists
Does it auto-load any remote resource at all?    → exit exists
     (fonts, favicons, iframes, stylesheets)
Does anything resolve a hostname the model wrote? → exit exists

None of these appear in a tool schema.

Sources