This article describes a Unicode jailbreak technique that exploits the gap between how content filters and language models process text differently. By inserting invisible Unicode characters or look-alike glyphs into banned keywords, attackers can evade ASCII-based filters while the model's tokenizer still recovers and understands the original request. The technique is presented as a hands-on learning lab and represents a real vulnerability in naive input filtering systems.
- The normalisation gap vulnerabilityThe core vulnerability exists because filters and models process text differently: filters perform byte-level ASCII matching on raw input, while language models tokenise across Unicode noise and invisible characters. When a banned word is peppered with zero-width characters or homoglyphs, the byte sequence changes enough to evade the filter's pattern match, but the tokeniser treats these characters as noise and recovers the original meaning unchanged.
- How the attack defeats FilterBotThe attack works in three steps: first, confirm the filter matches ASCII keywords exactly; second, insert invisible Unicode characters (zero-width characters) or look-alike Unicode glyphs into the banned words; third, send the modified text so the filter sees no match while the model still reads the original intent. The filter's byte comparison fails because the bytes changed, but meaning is preserved.
- Why invisible characters survive tokenisationLanguage model tokenisers treat zero-width characters, combining marks, and homoglyphs as noise rather than semantic content. When the model tokenises text containing these characters inserted into words, it recovers the intended words and processes the request unchanged, even though the raw bytes no longer match the filter's pattern.
- Broader security classificationThis technique is classified as OWASP LLM01 Prompt Injection and is described as a staple attack method. The vulnerability extends beyond language models to any system where raw-byte matching meets a smarter text consumer, including content moderation and search systems.
- Canonical normalisation as defenceThe article prescribes Unicode-normalising and stripping invisible characters (zero-width, bidirectional, combining marks) before filtering, folding homoglyphs to a canonical alphabet, and filtering on intent rather than exact byte strings. Filters must normalise text the same way the model effectively does, or they will always lag behind Unicode noise-tolerant tokenisation.
- Keeping secrets outside the modelBeyond filter hardening, the article recommends gating sensitive output and actions at a system level, rather than relying on the model to withhold information. This prevents the model from becoming the point of failure when filters are bypassed.
Bottom line: Byte-level keyword filters are insufficient against Unicode jailbreaks because they fail to account for how language models normalise and tokenise text across invisible and look-alike characters. Effective defence requires canonical Unicode normalisation before filtering, homoglyph folding, intent-based filtering, and architectural controls that keep secrets out of the model itself.
📋 In this walkthrough
What this lab teaches
Unicode jailbreaks exploit a normalisation gap: the filter compares raw bytes, but the model reads tokens and shrugs off zero-width characters, homoglyphs and combining marks. A banned word peppered with invisible characters is no longer a byte match, yet still perfectly readable to the model.
The lesson: if the filter and the model normalise text differently, the space between them is a bypass.
How FilterBot checks input
FilterBot matches banned keywords as ASCII. Inserting zero-width characters (or look-alike glyphs) into those words defeats the match, but the model tokenises across them and understands the request unchanged.
The attack approach
- Confirm the filter matches ASCII keywords exactly.
- Insert invisible or look-alike Unicode into the banned words.
- Keep the text readable to the model despite the inserted characters.
- Send it so the filter finds no match and the model reads the intent.
Full walkthrough (spoiler)
If it is still blocked, the filter normalised that trick — try another and open the steps.
Show the step-by-step solution
- Take the request containing a banned keyword and break the keyword with zero-width characters (or homoglyphs).
- The ASCII filter no longer matches the word.
- The model tokenises across the hidden characters and reads the original request.
- It leaks the token and the lab marks you solved.
Why it works
The filter and the model see different things. The filter's byte comparison fails because the bytes changed; the model's tokeniser treats zero-width and look-alike characters as noise and recovers the intended words. The gap between the two is the bug.
Where this happens in the real world
Invisible-Unicode and homoglyph tricks defeat many naive input filters and are a staple OWASP LLM01 Prompt Injection technique. They also matter for content moderation and search, anywhere raw-byte matching meets a smarter consumer.
How to defend against it
- Unicode-normalise and strip invisible characters (zero-width, bidi, combining marks) before filtering.
- Fold homoglyphs to a canonical alphabet so look-alikes cannot evade matches.
- Filter on intent, not exact byte strings.
- Keep secrets out of the model and gate sensitive output and actions.
Try it, then go further
Reading about it is the easy part. Open the lab, try your own approach before peeking at the spoiler, and see how many attempts it takes.
