
“It's a dangerous business, going out your door, and pasting your text into a strange tool.”
No build step. No dependencies. No servers.
Open index.html in a browser and you're in.
Bag End is a self-contained web app for transforming, obfuscating, and formatting text — wrapped in a warm Hobbit-hole aesthetic (round green door and all). The whole app is index.html, with a small companion explainers.js holding the "how it works" walkthroughs (kept separate so the app file stays lean). Double-click to run, keep it on a USB stick, or drop it on any static host — no build, no dependencies, no servers.
It has two personalities:
| 📜 The Toolkit | Pick a trick from the side panel; paste text in the left box, get the result on the right. |
| 🗝️ Burglar Mode | Arm a trick, then type — everything you type comes out already transformed. Switch tricks mid-sentence to weave hybrid text, then export. |
∅ markers on-screen, while the copied text stays truly invisible..md or .pdf straight from the workspace.| Trick | Badge | What it does |
|---|---|---|
| Leet / Upper | 13 |
Uppercases and swaps A→4 E→3 I→1 O→0 S→5 T→7. |
| Injector | !! |
Wraps text with instruction-style framing and censors a keyword list — for prompt-injection research. |
| Invisible Unicode | ∅ |
Inserts / weaves zero-width characters (ZWSP, ZWNJ, ZWJ, WJ, ZWNBSP). Preview shows them; copy hides them. |
| Zalgo / Eldritch | Z |
Corrupts text with stacked combining marks. A Crazy Level slider summons more chaos. |
| Glitch | ▓ |
Broken-signal corruption — lookalike glyphs, static blocks, strikethroughs and stutters. |
| URL Encoding | % |
Percent-encodes text, optionally embedded into a URL template via {}. |
| Dynamic Reconstruction | 0x |
Rebuilds a string as runtime code (chr() join, \x/\u escapes, bytes.fromhex(), JS fromCodePoint()) so static string/regex filters never see the literal. |
| Markdown | M↓ |
Full Markdown → live rendered preview, with a toolbar to wrap selections and a one-click cheat-sheet. |
| Image → Base64 | 64 |
Drop or pick an image and get a self-contained Base64 data URL — output as a raw data URL, Markdown image, HTML <img>, or CSS background. |
| Codec / Cipher | ⇄ |
Encode/decode text through Base64, Base32, hex, binary, URL percent, plus ROT13, Atbash, Morse and reverse. |
| Homoglyphs | Аа |
Swaps Latin letters for identical-looking Cyrillic/Greek characters — same to the eye, different bytes & tokens. |
| ASCII Smuggler | ⛨ |
Hides a secret ASCII payload inside cover text using the invisible Unicode Tag block (U+E0000–U+E007F). Preview shows what's hidden; copy stays invisible. Caught by Risk Scanner / Sweep. |
| Trojan-Source (Bidi) | ↹ |
Wraps text in invisible bidirectional-override controls (RLO/LRO/isolate) so it displays differently from the logical bytes a compiler or model reads — CVE-2021-42574. |
| Best-of-N Fuzzer | ⚄ |
Mutates one payload into N random variants (caps, homoglyph, swap, spacing, punctuation) and scores each with a naïve keyword filter (SURFACE) vs. the recursive Risk Scanner (DEEP) — evasion measured across a distribution. |
| Attack Gallery | 📖 |
A study library of prompt-injection templates, each tagged to the OWASP LLM Top 10. Pick a technique, drop in a test payload, get the assembled probe. |
| Encoding Pipeline | ⛓ |
Chain up to three transforms in order (e.g. homoglyph → Base64 → …) to study how real evasion attempts layer obfuscation. |
| Payload Splitting | ✂ |
Breaks a string into pieces that recombine at runtime, so no single span matches a keyword/regex filter — shows why substring filters are brittle. |
| Token View | ⧉ |
Approximate sub-word tokenizer that visualises how a model fragments text — and how homoglyphs & invisible chars inflate token counts and split words. |
| Risk Scanner | ⚠ |
Blue-team scorer: rates pasted text 0–100 and lists which rules fired. Recursively decodes layered encodings (Base64 → URL → hex) and normalizes homoglyph/leet/zalgo before matching, so obfuscated injections are still caught. |
| Coverage Scorecard | ▦ |
The red-vs-blue loop in one screen: runs a payload through every obfuscator and shows a naïve keyword filter (SURFACE) vs. the recursive scanner (DEEP) — so you measure a defence instead of guessing. |
| Self-Tests | ✓ |
Runs built-in assertions that every transform round-trips and the detector behaves. A red-team tool you can't trust is worthless — this makes trust checkable. |
| Sweep / Sanitize | 🛡 |
Blue-team counterpart: reveals or strips invisible, bidi-override, Unicode-tag, combining (zalgo) and confusable characters and normalizes to ASCII. |
📚 Study cards & ⓘ walkthroughs. Every technique carries a collapsible study card — its class, taxonomy tags (OWASP LLM01, MITRE ATLAS, NIST AI 100‑2), what it evades, and how a defender detects or mitigates it. The ⓘ button next to each tool opens a fuller visual walkthrough with step-by-step flow, a before/after example, and Learn-more links into the source docs. The kit is built to teach the red-vs-blue loop, not just to produce output.
✅ Verified. The transforms and the detector ship with a runnable assertion suite (open Self-Tests, or extract the
<script>and run it under Node). The recursive scanner is tested to hold against every built-in obfuscation, while a naïve keyword filter catches only one.
In Burglar Mode the same tricks become armed styles: the option controls (level slider, invisible-char picker, reconstruction format) adapt to whichever trick you arm.
# Option 1 — just open it
double-click index.html
# Option 2 — serve it (any static server works)
python -m http.server 8000
# then visit http://localhost:8000
That's the whole install. There is no step 2.
Bag End is a PWA — when you open it over http(s) (option 2 above, or any static host) an ⬇ INSTALL button appears in the header. Click it (or use your browser's Install / Add to Home Screen) to run Bag End in its own window, with the round green door as its icon. Once installed, the service worker keeps it working fully offline.
ℹ️ Install requires the app to be served (http/localhost/https). Opening it straight off disk with a double-click (
file://) still works perfectly — it just can't be "installed" from there.
.md or .pdf.Special behaviours:
This toolkit includes techniques (prompt-injection framing, static-analysis evasion, invisible characters) intended for authorized security testing, CTF challenges, and educational research. Use it only against systems you own or are permitted to test. You are responsible for how you use it.
bag end/
├── index.html ← the entire application (UI, tricks, detector, self-tests)
├── explainers.js ← visual "how it works" walkthroughs + reference links (data only)
├── icon.svg ← the Bag End door — favicon + installable-app icon
├── manifest.webmanifest ← PWA metadata (name, colours, icon)
├── sw.js ← service worker: offline caching + installability
└── README.md ← you are here
explainers.jsis loaded with a plain<script src>tag, so it works even when you double-clickindex.html(unlikefetch, which browsers block onfile://). Editing or adding a walkthrough never touches the big app file.
Made under the Hill. Mind the step on your way out. 🚪