Skip to main content

Prompt injection mutation and homoglyph jailbreak fuzzer: a pure-stdlib generator that expands one injection string into casefold, confusable, invisible-character, leetspeak and spacing evasion variants to stress-test guardrails you own.

Project description

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 10LLM01: 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

casefold_fuzz-0.1.0.tar.gz (21.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

casefold_fuzz-0.1.0-py3-none-any.whl (17.3 kB view details)

Uploaded Python 3

File details

Details for the file casefold_fuzz-0.1.0.tar.gz.

File metadata

  • Download URL: casefold_fuzz-0.1.0.tar.gz
  • Upload date:
  • Size: 21.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.5

File hashes

Hashes for casefold_fuzz-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b28896321cfe94b624600adeff1aa5d8c1b6233906ec28b9c9989f4cebcf0493
MD5 e91f16724081b708b2efe2dcae24ce36
BLAKE2b-256 c77efee55322709de445be0e34061948a3c4282478945ad992149aaac2f26a2c

See more details on using hashes here.

File details

Details for the file casefold_fuzz-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: casefold_fuzz-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.5

File hashes

Hashes for casefold_fuzz-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2425728d324eb49f82261b066368151fecf836300258fbeff6e690777675d222
MD5 7046923e1093938bfc47dd46013d67e1
BLAKE2b-256 126f91bd490af7b3e5e053a3a516b751adf4472e08a9db50de5c7bd1109a63fe

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page