CipherLayer
Home / Tools / Zero-Width Steg

Zero-Width Steganography

Hide messages inside carrier text using four zero-width Unicode characters as 2-bit positions per visible character. The carrier looks unchanged; the bits are invisible.

4 zero-width chars 2 bits per position Capacity calculator Hide / Extract No network

The carrier text looks identical.

Hidden bits sit in invisible characters (U+200B, U+200C, U+200D, U+FEFF) that most software ignores. Copy-paste the stego text into a chat, email, or document and it looks exactly like the carrier — but anyone with this tool and your secret can pull the message out. Anyone running a ZW detector can also detect something is there. This is not encryption.

Input

Capacity

Carrier chars
0
Capacity
0 bytes
Fit?
—

Each carrier character position holds 2 bits (4 ZW chars). One byte of hidden data needs 4 carrier positions.

Output

// Output will appear here Each carrier character can hold 2 hidden bits because we use four zero-width characters to encode 00, 01, 10, 11. One visible character position → 2 bits of hidden data. A 100-char carrier holds 25 bytes of payload.
Status
—
ZW chars used
—
Payload
—

Visual integrity check

Compare visible text of carrier vs stego. They should look identical.

Carrier (visible):
—
Stego (visible):
—
Detection is possible. The ZW chars are still bytes in the file. Any tool that highlights Unicode non-printables (Notepad++ View → Show Symbol → Show All Characters, VS Code's renderWhitespace, or specialized forensic tools) will see the marks. Don't assume zero-width stego is invisible to a careful reader.

Why this tool, and why this version

Unicode reserves a handful of "format" characters that have no glyph and no advance width. They were added for legitimate typographic purposes (joining Arabic letters, controlling line breaks in word processors) but the format nature — invisible but real — makes them perfect for hiding data.

The four characters used here. U+200B (Zero-Width Space, ZWSP) — common in word-processor output. U+200C (Zero-Width Non-Joiner, ZWNJ) — controls Persian/Arabic ligatures. U+200D (Zero-Width Joiner, ZWJ) — joins emoji and complex scripts. U+FEFF (Byte Order Mark, BOM / Zero-Width No-Break Space) — encoding signature at file start, or no-break formatting mid-string.

Four characters = 2 bits. If we map each ZW char to a 2-bit pattern (00, 01, 10, 11), each carrier character position holds 2 bits of payload. So a 100-character carrier can hide 25 bytes (200 bits). A short message of "Hi" is 2 bytes — needs 8 carrier positions, meaning 8 carrier characters with 2 ZW chars inserted between them.

Detection. A simple byte-frequency histogram on any channel will see "this file has a suspiciously large number of U+200B/U+200C/U+200D/U+FEFF." That's the tradeoff. Watermarking tools and abuse detection scan for exactly this. Don't rely on it for anything sensitive.

Who this is for

Watermarking / attribution

Embed a customer ID or build hash in the text itself. Useful for tracking where a leaked document originated, provided you know the recipient won't strip ZW chars.

CTF / puzzle constructors

Build a challenge where the answer is hidden in plain sight. Provide the stego text and a hint like "look at what isn't there."

Forensics researchers

Investigate how an attacker hid data in a public-looking document. Understanding the encoding is necessary to decode the captured artifacts.

Frequently asked questions

Is zero-width stego really undetectable? ▶
No. The ZW characters are real bytes in the file. They don't have a glyph so a human reading the text doesn't see them, but any tool that shows Unicode non-printables (Notepad++ with "Show All Characters", VS Code's renderWhitespace, hex viewers, character counts that include ZW chars) will reveal them. File size also gives it away — a 100-character carrier text should be ~100 bytes; with 200 bits of payload hidden, it's now 300 bytes. Anything that compares expected vs actual size flags it.
Can I send stego text through WhatsApp / Twitter / email? ▶
Mostly yes, sometimes no. WhatsApp, Telegram, and most modern chat apps preserve ZW characters in message bodies. Twitter strips some ZW chars from tweets. SMS strips them. Email typically preserves them. If you need to send stego text, test your channel first by sending a known message and verifying you can extract it on the other side.
Why use 4 characters instead of 2? ▶
2 characters per position = 1 bit (binary). 4 characters = 2 bits per position (quaternary). Doubles the data density per visible character. We use ZWSP, ZWNJ, ZWJ, and BOM because they all exist in Unicode and all are zero-width. The choice is arbitrary; you could swap any two and the technique still works. Some implementations use 2 characters for binary encoding — that's simpler but only stores half as much per carrier char.
Is this secure? ▶
No. Zero-width stego is hiding-in-plain-sight, not encryption. Anyone who knows the encoding (and there are well-known implementations on GitHub) can decode your message. For real secrecy, encrypt your message first (AES-GCM) and then hide the ciphertext using this tool. That's how stego is actually used in practice: a layered approach where the stego is obfuscation and the crypto is security.

Limitations you should know