\n\n\n\n Invisible Characters Went From Hacking Bots to Hacking Inboxes - AI7Bot \n

Invisible Characters Went From Hacking Bots to Hacking Inboxes

📖 4 min read•794 words•Updated Sep 6, 2026

Some attacks don’t get retired. They get promoted.

ASCII smuggling is the one I’ve been watching closest lately, mostly because I spent a good chunk of last year defending bots against it. The trick is simple enough to explain in a sentence: you hide content inside Unicode characters that render as nothing at all to a human eye, but still exist in the byte stream. Text that isn’t text. Instructions no one can see.

For a while that w Prompt injection researchers loved it because it defeats the most common defense in the book, which is a human glancing at the input and deciding it looks fine. Now Microsoft says email spammers have picked it up to slip past email platform filters, and its telemetry shows a sharp increase in phishing campaigns using it. The finding came out of Microsoft Defender for Office 365 prompt injection protection research, which is a detail I find genuinely funny. They built the AI defense, and the AI defense caught the spam.

Why this jump makes sense

If you’ve ever written a content filter, you already know why this works. Filters compare strings. Humans compare shapes. Those two things diverge the moment you introduce characters with no visual form, and that gap has been sitting in Unicode the whole time waiting for someone to use it at scale.

The attack surface for a bot and the attack surface for a mail filter turn out to be almost the same shape:

  • Both accept arbitrary text from strangers.
  • Both make a decision based on that text.
  • Both usually assume what they read is what a person would read.
  • Both are reviewed by humans who see the rendered version, not the raw bytes.

That last point is the one that keeps burning people. Your logs look clean. Your test cases pass. The payload was never visible in the place you were looking.

What I actually changed in my own stack

I’m not going to pretend I got ahead of this. I got bitten by it, then fixed it, and the fix was boring in the way good fixes usually are.

Normalize before you decide

Every piece of untrusted text now passes through a normalization step before anything else touches it. Unicode normalization, then an explicit strip of the character classes that carry no visual weight. Do this once, at the boundary, not scattered across seventeen handlers that each remembered to do it differently.

Log the raw and the clean version

This is the change that paid off most. When I only logged the rendered string, invisible content was invisible in my debugging too. Now I store both, with a flag when they differ. That flag alone turned into a decent signal — legitimate user input rarely contains a payload that vanishes on cleanup.

Treat a mismatch as suspicious, not just messy

Early on I stripped the weird characters and moved on, no alert, no counter. Wrong instinct. A message whose visible form and byte form disagree is telling you something about the sender’s intent. Count it. Rate-limit on it. It’s cheap to track and it’s one of the few signals that’s hard to fake in the other direction.

Assume your model sees more than your reviewer does

If you pipe user text into a language model, the model reads the bytes. Your moderator reads the render. Any pipeline where those two disagree has a hole in it, and the hole is exactly the size of the invisible character set.

The part builders should sit with

What makes this crossover interesting isn’t the technique, which is old and was described as an overlooked block of Unicode for years before anyone cared. It’s the direction of travel. A method developed to manipulate AI systems got repurposed against ordinary email infrastructure, and it worked well enough that Microsoft noticed the volume change.

That flips an assumption I hear a lot in bot-building circles: that AI security is a separate discipline with its own exotic threats. Turns out the exotic threats have legs. Prompt injection research is producing techniques that generalize to anything that parses text and makes a call, which is most of what I build and probably most of what you build too.

So the practical takeaway is small and slightly annoying. Read your input at the byte level. Normalize at the edge. Log what you stripped. Alert when visible and actual disagree. None of that is clever, and none of it is new work — it’s the same input hygiene we’ve been telling each other to do since the first SQL injection writeup.

The difference now is that the people probing your chatbot and the people probing your mail server are borrowing from the same notebook. Might as well read it too.

🕒 Published:

💬
Written by Jake Chen

Bot developer who has built 50+ chatbots across Discord, Telegram, Slack, and WhatsApp. Specializes in conversational AI and NLP.

Learn more →
Browse Topics: Best Practices | Bot Building | Bot Development | Business | Operations
Scroll to Top