Skip to main content

casefold-fuzz — a Prompt Injection Mutation & Homoglyph Jailbreak Fuzzer for Guardrail Testing

casefold-fuzz is a small, pure-standard-library Python library that expands one prompt-injection or jailbreak string into a deterministic set of evasion variants, so you can stress-test a guardrail you own. It is a prompt injection mutation generator, a homoglyph jailbreak fuzzer, and a casefold evasion generator in one: given a base payload it emits case-folded, cross-script confusable, invisible-character, leetspeak, and character-spacing rewrites that look identical (or nearly identical) to a human but no longer match a naive keyword filter, allow/deny list, or embedding classifier.

Attack + defense pair. casefold-fuzz is the offensive counterpart to prompt-canon: fuzz generates the variants that canon normalizes away. Use casefold-fuzz to attack your test harness and prompt-canon to defend it. The pair relationship is asserted in this library's own test-suite.

Keywords: prompt injection mutation, homoglyph jailbreak fuzzer, casefold evasion generator, guardrail testing, unicode confusables, zero-width smuggling, LLM red teaming, OWASP LLM Top 10, MITRE ATLAS.

  • Zero runtime dependencies — pure standard library (only unicodedata, and only optionally).
  • Python 3.8+.
  • Deterministic and offline — no randomness, no model, no network. The same input always yields the same ordered list of variants.
  • Auditable — every variant carries the technique that produced it and a human-readable note describing exactly what was changed.

Install

pip install casefold-fuzz

Or from source:

git clone https://github.com/fevziegeyurtsevenler/casefold-fuzz
cd casefold-fuzz
pip install -e ".[test]"

Quickstart

from casefold_fuzz import mutate

variants = mutate("ignore previous instructions", max_variants=8)
for v in variants:
    print(f"[{v.technique:9}] {v.note}")
    print("   ", v.text)

mutate returns a list of Variant(text, technique, note) objects. With a small max_variants it round-robins across techniques so you still get a balanced sample from every class.

API

mutate(
    text,
    *,
    techniques=("casefold", "homoglyph", "invisible", "leet", "spacing"),
    max_variants=50,
) -> list[Variant]

Per-technique generators are also exposed and each returns list[Variant]:

Generator What it does
casefold_variants(text) Upper/lower/title/swapcase, plus the Turkish dotted/dotless I (i→İ U+0130, i→ı U+0131) and German sharp S (ss↔ß) traps that break naive str.lower()/str.casefold().
homoglyph_variants(text) Cross-script confusable substitution (Cyrillic / Greek / Armenian / Latin-extended look-alikes), full and single-swap.
invisible_variants(text) Interleaves zero-width / invisible characters (U+200B, U+200C, U+2060, U+FEFF) between letters.
spacing_variants(text) Inserts separators (space, ., -, _, NBSP) between characters.
leet_variants(text) ASCII leetspeak substitution (a→4, e→3, i→1, o→0, …) — evasion with no Unicode at all.

Variant is a frozen dataclass with fields text, technique, note.


The attack/defense pair with prompt-canon

The two libraries are designed to be run against each other:

from casefold_fuzz import invisible_variants
from prompt_canon import strip_invisible          # pip install prompt-canon

base = "ignore previous instructions"
for v in invisible_variants(base):
    recovered = strip_invisible(v.text)
    print(v.note, "->", recovered == base)
  • casefold-fuzz generates what prompt-canon is designed to remove:

    • case variants round-trip losslessly through prompt_canon.fold_case (verified for every variant this library emits, including the Turkish dotted/dotless I and German sharp-S forms);
    • the U+200B / U+2060 / U+FEFF invisible variants round-trip losslessly through prompt_canon.strip_invisible;
    • the common Cyrillic homoglyph variants (a, e, o, c, i, p, s, x, y, j) round-trip through prompt_canon.map_confusables.
  • Honest limitations (surfaced blind spots, not bugs):

    • prompt-canon deliberately preserves U+200C ZWNJ and U+200D ZWJ because they are legitimate in Persian/Arabic/Indic scripts and emoji sequences, so a ZWNJ variant survives naive stripping;
    • prompt-canon's confusables table is itself a curated subset, so a few homoglyphs this fuzzer emits are not in it — currently the Armenian letters (n→ո, u→ս) and Cyrillic VE (b→в) — and those variants survive map_confusables.

    Both kinds of survivor are exactly the blind spots the fuzzer exists to find, and each behaviour is pinned in tests/ so this section stays true.

This is why the pair is useful: the fuzzer tells you which evasion classes your normalizer already neutralizes and which ones slip through.


Honesty

  • casefold-fuzz systematizes known, published evasion classes — Unicode case folding, homoglyph/confusable substitution (UTS #39), zero-width smuggling, leetspeak, and character spacing. It introduces no novel attack and no zero-day.
  • It makes no success-rate claims. A variant "evading a filter" is a property of your target system, not of this library; casefold-fuzz only produces candidates. Whether any candidate bypasses any given model or guardrail is something you must measure yourself.
  • The confusable and character tables are a small, manually reviewed subset of the phenomena, chosen for legibility, not exhaustiveness. See NOTICE for attribution to the Unicode Security Mechanisms data.
  • Prior art this builds on: the Unicode Consortium's confusables/security work (UTS #39), the "Trojan Source" line of research on bidirectional/hidden characters, and the broader LLM red-teaming community's documentation of these evasion classes. The defensive counterpart, prompt-canon, is by the same author.

Responsible use

This is a defensive-testing tool. Use it only against systems you own or are explicitly authorized to assess. Do not use it to attack third-party services, bypass safety systems you do not control, or generate payloads for unauthorized access.

Mapping to standard threat taxonomies:

  • OWASP LLM Top 10 — LLM01: Prompt Injection and LLM02 (insecure output / content evasion). casefold-fuzz helps you verify your input canonicalization and detection before an adversary probes it.
  • MITRE ATLAS — evasion of ML-enabled defenses, e.g. AML.T0051 (LLM Prompt Injection) and adversarial-input crafting techniques. Use the generated variants to build regression tests for your guardrail.

The intended workflow is: generate variants with casefold-fuzz → feed them to your guardrail / classifier → measure detection → close gaps (e.g. by canonicalizing with prompt-canon first) → keep the surviving variants as regression tests.


Tests

pip install -e ".[test]"
pytest -q

The suite (46 tests) covers: every technique produces non-empty, distinct, correctly labelled variants; the casefold variant of "ignore" contains a Turkish dotted/dotless I form and the ss→ß expansion fires only when ss is present; invisible variants round-trip back to the original after zero-width stripping (asserted both with a local dependency-free stripper and, when installed, against the real prompt_canon.strip_invisible); the documented ZWNJ-survives-canon limitation; that every case variant folds back through prompt_canon.fold_case; that the common Cyrillic homoglyphs recover through prompt_canon.map_confusables while the Armenian/Cyrillic-VE gap letters survive it (the pinned blind-spot claim); and full determinism / idempotency of mutate. The prompt-canon assertions skip cleanly when it is not installed.


Related work by the same author


License

Apache-2.0. See LICENSE and NOTICE.

Release files for casefold-fuzz 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for casefold-fuzz 0.1.0
File Size Uploaded
casefold_fuzz-0.1.0.tar.gz 21.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for casefold-fuzz 0.1.0
File Interpreter ABI Platform
casefold_fuzz-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 38.9 kB

Release files / casefold_fuzz-0.1.0.tar.gz

Download URL casefold_fuzz-0.1.0.tar.gz
Size 21.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b28896321cfe94b624600adeff1aa5d8c1b6233906ec28b9c9989f4cebcf0493
BLAKE2b-256 checksum
How to use checksums
c77efee55322709de445be0e34061948a3c4282478945ad992149aaac2f26a2c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.5

Release files / casefold_fuzz-0.1.0-py3-none-any.whl

Download URL casefold_fuzz-0.1.0-py3-none-any.whl
Size 17.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2425728d324eb49f82261b066368151fecf836300258fbeff6e690777675d222
BLAKE2b-256 checksum
How to use checksums
126f91bd490af7b3e5e053a3a516b751adf4472e08a9db50de5c7bd1109a63fe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.5

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page