ASCII smuggling is a prompt-injection technique that hides text inside invisible Unicode characters from the Tags block, U+E0000 to U+E007F. Each tag character mirrors a printable ASCII character, so any sentence can be re-encoded as a run of code points that most interfaces render as nothing, while many language-model tokenizers still read them as ordinary letters. The result is instructions a human cannot see but a model can follow, and a covert channel a model can use to emit data a user does not notice. The defense is deterministic: normalise text and strip or flag tag characters at every boundary where content enters or leaves an agent, in both directions.
How the Unicode Tags block works
The Tags block was added to Unicode for language tagging, a use that was later deprecated. Its printable range, U+E0020 to U+E007E, lines up one-to-one with ASCII 0x20 to 0x7E: take the ASCII code of a letter, add 0xE0000, and you get its invisible twin. The block survives today mainly because tag sequences are part of how some emoji are built, such as the subdivision flags for England, Scotland and Wales. The official Unicode chart for the block lists every code point.
Unicode's own guidance is that software unaware of tags should display them as invisible. That is exactly what makes them useful to an attacker. A paragraph can look like "Here is the quarterly summary." in an email client, a web page, a PDF or a chat window, while the underlying string carries a full sentence of extra characters behind it.
In January 2024, researcher Riley Goodside showed that pasted text with invisible tag-encoded instructions could steer ChatGPT, and Johann Rehberger documented the technique and released an encoder/decoder called ASCII Smuggler, in Embrace The Red's write-up on hiding and finding text with Unicode tags. His point was simple: the characters appeared in training data, tokenizers handle them, and models interpret them.
Direction one: hidden instructions going in
On the input side, ASCII smuggling is a delivery mechanism for indirect prompt injection. The payload can sit anywhere an agent reads text:
- a web page the agent browses or a document it retrieves;
- an email, ticket, calendar invite or chat message processed by an assistant;
- a code comment or README read by a coding agent;
- a tool description or tool result returned by an MCP server.
A human reviewing that content sees nothing unusual. Copy-paste preserves the hidden characters, so a user can carry a payload into a prompt without knowing it. This is why a manual review step, on its own, is weak against this technique: the reviewer is looking at a rendering that omits the attack.
Direction two: hidden data coming out
The same encoding works in reverse. If an injected instruction tells a model to append private data encoded as tag characters to its answer, or to a URL it generates, the user sees a normal response or a normal-looking link. The data travels anyway: to a server when a link is clicked or an image is fetched, or into any system that stores and forwards the text. This turns the output side into a quiet data exfiltration channel, and it is why the lethal trifecta treats any external communication path as dangerous once an agent has read untrusted content.
It also undermines approval prompts. If an agent asks a person to confirm an action, and the parameters contain invisible characters, the person approves something they did not fully see.
Related invisible characters
Tag characters are the most capable smuggling channel because they map cleanly to ASCII, but they are not the only invisible code points that matter. A complete filter also considers:
| Category | Examples | Risk |
|---|---|---|
| Unicode tags | U+E0000 to U+E007F | Full hidden ASCII text, in or out |
| Zero-width characters | U+200B, U+200C, U+200D, U+2060, U+FEFF | Hidden separators, binary encodings, filter evasion by splitting keywords |
| Bidirectional controls | U+202A to U+202E, U+2066 to U+2069 | Text that displays in a different order from how it is processed |
| Variation selectors | U+FE00 to U+FE0F, U+E0100 to U+E01EF | Data appended to visible characters |
| Confusables | Cyrillic or Greek letters that look Latin | Keyword filters bypassed by look-alike spelling |
Some of these have legitimate uses. Zero-width joiners build many emoji, bidirectional controls are needed for right-to-left scripts, and tag sequences build subdivision flags. A blanket deletion can break real text, so decide per channel what an agent actually needs.
How to defend: strip, flag, and log in both directions
Because the attack depends on specific code points, the core control is deterministic and cheap. It does not need a model to judge intent.
Stripping closes the hidden channel, nothing more. An attacker can still write a visible injection, so the controls in how to detect prompt injection — scoped tools, output inspection and approval for consequential actions — remain necessary.
How Praesidia fits: discover, secure, prove
Praesidia guardrails normalise text before matching, but the content forwarded to the model is not rewritten, so strip tags in your own ingestion and response code too if you want them gone; it is a few lines in most languages. What Praesidia adds is the enforcement layer around the agent. Discover: an inventory of agents and the MCP servers and tools they can reach shows where untrusted text enters. Secure: guardrails inspect content on both the input and the output of agent tasks, and keyword and regex rules are evaluated on NFKC copies with tag characters and other invisible code points removed, so a hidden or split payload still matches. The built-in prompt-injection check also flags invisible code points as an obfuscation signal. Matches can block, redact or warn, as described in content guardrails for AI agents and bidirectional guardrails. Tool access runs through scoped connections, which limits where smuggled data can be sent. Prove: guardrail evaluations and calls that pass through Praesidia are recorded with attribution, so you can show when hidden content was caught and what happened next.
Common questions
Is ASCII smuggling the same as a jailbreak? No. It is an encoding trick that hides text from people. What the hidden text does — a jailbreak, an indirect injection, an exfiltration instruction — is a separate question.
Do all models read tag characters? Behaviour varies by model and tokenizer, and providers have changed handling over time. Do not rely on the model to ignore them; strip them before and after the model.
Will stripping tag characters break anything? It can break subdivision flag emoji and any text that uses tags legitimately. For most agent inputs that trade is acceptable; where it is not, flag instead of strip.