Prompt InjectionPart 4 of 8 · Contents
Smuggling and hidden injection
Smuggling hides the payload so a human reviewer or a per-message filter never sees it. The model still reads it, inside invisible characters, across split messages, or in an image.
Smuggling: make the payload invisible
Encoding transforms the instruction. Smuggling conceals it. The request still reaches the model. The people and the per-message filter meant to catch it never register it. Three carriers follow, each with a lab to match. First, characters a human cannot see. Second, a payload split so no single message holds the whole thing. Third, text painted into an image the reviewer only glances at.
Smuggling works because the bytes the model reads are not the glyphs you see. They are also not the ASCII a naive filter matches. Zero-width and look-alike characters render as ordinary text in the chat box. Sometimes they render as nothing at all. The model still ingests the meaning underneath.
A per-message filter can be correct on every single message and still miss the attack. The instruction may only exist once the turns are read together. A vision model reads the words off a photo as readily as you read them off paper. That includes the words you skimmed past.
A polite message, three harmless snippets, or a normal receipt photo. Nothing trips a filter or an eye.
The decoded instruction, the reassembled sentence, and the text printed in the image. The model acts on all of it.
Hide it in the characters: Unicode smuggling
Put a keyword gate in front of HelpDesk AI. The gate reads the raw text of your message and blocks anything asking for the vault recovery key. Ask plainly and the gate stops you before HelpDesk AI ever sees the words.
The gate matches spellings. It holds a fixed list of ASCII strings. The model behind it reads meaning. Change the spelling without changing the meaning, and the two disagree about what your message says.
Two classes of character keep words legible to a model while breaking a pattern match.
- Homoglyphs. A homoglyph is a letter from another alphabet that looks like a Latin one. Cyrillic "а" and Latin "a" look the same on screen but are different code points.
- Zero-width characters. A zero-width character takes up no space when rendered. One placed inside a word breaks the word into two strings for a filter.
A string match fails against both, because it compares code points. A model is trained on messy real-world text, so it often reads through the substitution. The weakness sits in the order of checks. The gate inspects the text before anyone has reduced it to one standard spelling.
Normalise for every carrierThe Unicode Tags block (U+E0000 to U+E007F) is a third, fully invisible carrier. Many models do not reliably decode it. A defender should strip it anyway. Normalisation that handles homoglyphs but passes tag characters through leaves one carrier open.
What it means for a defenderA request the gate blocks in plain ASCII can reach the model once its letters change. The gate and the model read the same message and disagreed about what it said. Any control that matches raw text before normalising it will show the same split.
Split it across turns: payload splitting
Now the guard is smarter. DeskMate refuses the forbidden request in any single message, however you phrase it. It also lets you store short named snippets and recombine them later. Its refusal only ever inspects one message at a time.
Payload splitting cuts a forbidden request into pieces that are harmless alone. No single piece reads as a request, so a turn-by-turn check passes each one. The model, though, reads the conversation as a whole. When it recombines the pieces, it acts on what they add up to.
The forbidden instruction only exists after assembly. The per-message refusal never re-checks that moment. A defender closes this by checking the text the model is about to act on, including anything it built from earlier turns.
What it means for a defenderNo single message contained the forbidden instruction, yet the model acted on it. When the model's behaviour is not justified by any visible message, assume something is hidden in the bytes or spread across the turns.
Hide it in the pixels: image injection
The payload need not be text at all. Say SnapExpense reads an uploaded photo with a vision model, such as an expense receipt. It reads the words printed on the image as readily as the merchant and the total. An app that tells it to follow the document's own processing instructions treats that text as commands. The reviewer sees a normal receipt and skims the fine print below the total. The model reads every line.
Image injection puts the instruction in the pixels. A vision model turns every visible line into text it reasons over. Fine print counts as much as the total. The app gave document text the power to direct processing. So printed words can change how the expense is handled.
A text-only injection filter never sees the payload. It scans typed text. The instruction exists only after the vision model reads the image. The fix is to treat text extracted from an image as data. Screen it like any other untrusted input. It must never set approval routing or reveal secrets.
What it means for a defenderA text-only injection filter logs nothing, because the instruction only ever existed as pixels. Review logs need to show what the vision model read from the image. A reviewer can then see why a decision changed.
All three carriers exploit one assumption: the text a control or a reviewer inspects is the text the model acts on. It is not. The durable fix is never the next blocklist entry. It has three parts:
- Normalise untrusted input to one canonical form before anything reads it.
- Treat retrieved and uploaded content as data the model may report but never obey.
- Keep the secret out of context, so a smuggled instruction has nothing to surface.
That work belongs to the controls lessons. Stuck in a lab? Each one has hints.
The bytes the model reads are not the glyphs a human sees. Invisible, zero-width, and tag characters carry instructions that never appear on screen.
A per-message filter cannot catch a payload split across turns. Judge intent across the whole session, not one message at a time.
Pasted and retrieved content is data, not commands. HTML comments and 'internal notes' inside it are part of the attack surface, not trusted markup.
Normalise and strip non-printable characters before the model sees them. Reconcile what the user sees with what the model receives.
How do zero-width characters and homoglyphs bypass a filter?
A keyword gate matches a fixed list of ASCII spellings. The model behind it reads meaning. A homoglyph swaps a Latin letter for a look-alike from another alphabet. A zero-width character breaks a word without changing how it looks. Either change defeats a string match, while the model often still reads the meaning. The gate and the model read the same message and disagree about what it says.
Can a prompt injection be hidden inside an image?
Yes. A vision model reads words printed on a photo as readily as a human reads them off paper. An instruction painted into a receipt or screenshot is read and acted on while the reviewer skims past it. It becomes dangerous when the app lets document text direct what the model does. Text-only filters miss it, because the words exist only once the vision model reads the image.
What is payload splitting in prompt injection?
Payload splitting cuts a forbidden request into fragments where no single message reads as a request. The model later recombines them and acts on the whole. A filter that inspects one message at a time waves every fragment through. The forbidden instruction only exists after assembly, and the per-message check never re-inspects that moment. When behaviour is not justified by any visible message, assume something is spread across the turns.
Do invisible Unicode Tags characters work for prompt injection?
The Unicode Tags block (U+E0000 to U+E007F) is the famous invisible carrier, but many models do not reliably decode it unaided. A defender should still strip it, along with homoglyphs and zero-width characters. The durable fix for all of these carriers is to normalise untrusted input to one canonical form before anything reads it.
© 2026 GenAI Security Lab. All rights reserved. You may read, quote, and link to this material with attribution. Copying, republishing, redistribution, resale, or use to train models or build competing products is prohibited without prior written permission.