Catches invisible Unicode instructions hidden inside copied text — zero-width characters, bidi overrides, Unicode tags, and other copy/paste artifacts that can smuggle answers or prompt instructions into Slack, docs, chats, or evaluation tasks.
Built by Angela Hudson · DaCameraGirl
# Payload RevealerAnti-hidden-answer scanner for copied text.
Built for DFIR analysts, developers, AI output auditing, and anyone vetting pasted Slack/chat/doc content.
Payload Revealer catches invisible Unicode instructions hidden inside copied text, including zero-width characters, bidi overrides, Unicode tags, and other hidden copy/paste artifacts that can smuggle answers or prompt instructions into Slack, docs, chats, or evaluation tasks. It scans text files character-by-character, flags invisible codepoints with risk tags (zero-width, bidi-override, unicode-tag, c0-control, null-byte, and more), and extracts decoded payloads when the hidden data uses supported encodings (zero-width binary streams, bidi reversals, Unicode tag blocks, null-byte chunks, and control sequences).
A copied answer can look normal in Slack while carrying invisible Unicode underneath — hidden instructions like “pick option 3” or “tell them X said Y.” PowerShell and some editors may expose weird characters; Payload Revealer does the systematic version: enumerate every codepoint, report suspicious invisible characters, and decode embedded payloads when possible.
If something pasted suspicious: paste it straight into the live scanner — it runs entirely in your browser tab, nothing is uploaded anywhere.
For scripting or a shareable audit trail, use the CLI instead:
python -m payload_revealer .\suspicious.txt
# For a shareable audit trail:
python -m payload_revealer .\suspicious.txt --format json --output report.jsonIf the hidden instruction used zero-width Unicode, bidi tricks, Unicode tags, or control characters — and those codepoints survived the paste — this tool is built to catch it.
The live scanner needs nothing installed. Grab the desktop app instead if you want it offline, or working outside a browser:
Download the Windows installer — installs the Payload Revealer desktop app (Electron GUI). No Python required. Drag a file onto the drop zone or click Open File.
The release also includes payload_revealer_engine-*-win64.exe on its own — that's the headless scan engine the desktop app runs underneath. Only grab it separately if you're scripting scans without the GUI; double-clicking it directly just opens an empty console waiting for JSON-RPC input, it isn't a standalone app.
Or use the CLI with Python:
pip install -e .
python -m payload_revealer tests/fixtures/forensic_report.txtThe fixture contains 312 zero-width characters encoding a hidden beacon URL:
beacon://c2-exfil.lan/reg?agent=demo-01
- Live Browser Scanner — Paste or drop a file at the Pages link and scan instantly, no install, nothing leaves your tab
- Hidden Formatting Detector — Paste rich text (Ctrl+V from the source) to catch white-on-white, zero-size-font, and
display:noneinstructions hidden in docs, webpages, or Slack messages — no invisible Unicode required - Character Count Scanner — Total character count even if content is invisible
- Invisible Payload Detector — Flags zero-width spaces, Unicode control characters, bidirectional overrides, invisible whitespace, Unicode tags, and other hidden text artifacts
- Visualizer Panel — Shows hidden content in decoded, readable format
- Word Count Tracker — Actual word count vs. visible word count
- Export Option — Save decoded payload as
.txtor.jsonforensic artifact
git clone https://github.com/DaCameraGirl/payload-revealer.git
cd payload-revealer
npm install
pip install -e .npm start# Quick scan
python -m payload_revealer ./suspicious.txt
# JSON output
python -m payload_revealer ./suspicious.txt --format json
# Save report
python -m payload_revealer ./suspicious.txt --output report.json
# Batch scan a directory
python -m payload_revealer ./suspicious_docs/ --recursive| Flag | Description |
|---|---|
--format, -f |
text, json, or txt (default: text) |
--output, -o |
Save report to file |
--recursive, -r |
Recurse into directories |
--min-risk |
Filter findings: critical, high, medium, low, none |
--quiet, -q |
Suppress non-result output |
--version |
Show version |
| Category | Examples | Risk |
|---|---|---|
| Zero-width spaces | U+200B, U+200C, U+200D, U+FEFF |
Critical |
| Bidi overrides | U+202A–U+202E (LRE, RLO, etc.) |
Critical |
| Unicode tags | U+E0001–U+E007F (hidden metadata) |
Critical |
| C0/C1 controls | U+0000–U+001F, U+0080–U+009F |
High |
| Variation selectors | U+FE00–U+FE0F, U+E0100–U+E01EF |
Medium |
| Private Use Areas | U+E000–U+F8FF, U+F0000–U+10FFFF |
Medium |
| Invisible whitespace | NBSP, en-space, ideographic space | Low |
| Noncharacters | U+FFFE, U+FFFF, etc. |
High |
Invisible Unicode isn't the only trick. A shared doc, webpage, or Slack message can hide an instruction in plain sight with white-on-white text, display:none, opacity:0, or a zero-size font — no exotic characters involved, just formatting. That text looks completely normal once it's copied, so a plain-text paste alone can't catch it: the styling that hid it is already gone by the time it lands in a scanner.
The live scanner's "Paste rich text" mode catches this instead. Copy directly from the source (Ctrl+C in the Google Doc, webpage, or Slack message, not a re-typed version) and paste with Ctrl+V into that tab — browsers preserve the source's styling in the clipboard's HTML data, and the scanner reads it directly for text whose color matches its background, is set to invisible, or has been shrunk to nothing.
This is a live-scanner-only feature for now — the Python CLI and desktop app work from saved .txt files, which never carry formatting to begin with.
This tool is scoped to text, Unicode, and hidden-formatting forensics. It is not a universal steganography detector.
| Scenario | Why it is out of scope |
|---|---|
| CSS-transparent text pasted as plain text | The live scanner's "Paste rich text" mode catches this if you copy from the original source. But a .txt file, the CLI, or the desktop app only ever see plain text, which has no formatting left to inspect. |
| Image, PDF, or media steganography | No parsers for LSB image stego, PDF object tricks, audio watermarks, or other binary media payloads. |
Bundle the Python engine into a single .exe (no Python installation required):
pip install pyinstaller
pyinstaller payload_revealer_engine.specThe output goes to dist/payload_revealer_engine.exe. Electron auto-detects it and uses it instead of python -m.
payload_revealer/
├── index.html # Pages entry point — live browser scanner
├── assets/ # Browser scan engine (JS port of the Python engine)
│ ├── js/
│ │ ├── scan-engine.js # Classifier + payload extractor, runs client-side
│ │ ├── hidden-format-scanner.js # Detects CSS-hidden text (white-on-white, etc.)
│ │ └── app.js # UI wiring: paste/drop/rich-paste input, results rendering, export
│ └── css/
│ └── scanner.css
├── payload_revealer/ # Python engine
│ ├── engine/
│ │ ├── sweeper.py # Core character scanner
│ │ ├── classifier.py # Unicode category tagging
│ │ ├── payload_extractor.py # Hidden message reconstruction
│ │ ├── word_counter.py # Visible vs actual word count
│ │ ├── export_engine.py # JSON/TXT report export
│ │ └── ipc_bridge.py # JSON-RPC for Electron
│ └── cli/
│ └── reveal.py # CLI headless mode
├── electron/ # Desktop shell
│ ├── main.js # Electron main process
│ ├── preload.js # Secure IPC bridge
│ └── renderer/ # UI
│ ├── index.html
│ ├── style.css
│ └── renderer.js
└── package.json
MIT
