Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix: extend unicode-invisibles-strip to cover bypass code points#204

Merged
twschiller merged 1 commit into
mainfrom
fix/unicode-invisibles-extra-codepoints
Jun 6, 2026
Merged

Fix: extend unicode-invisibles-strip to cover bypass code points#204
twschiller merged 1 commit into
mainfrom
fix/unicode-invisibles-extra-codepoints

Conversation

@twschiller

Copy link
Copy Markdown
Contributor

Summary

Closes one item from the red-team audit in #203 (Critical, XS).

A single soft hyphen (U+00AD) — or any of the other code points added here — inserted inside a trigger word defeats every regex-based rule in the catalog: prompt-injection-redact, secrets-redact, pii-redact, confirmshame-sanitize, disguised-ad-flag. The verb the agent reads via textContent is still semantically intact, but \b<verb>\b no longer matches because the invisible breaks the word boundary.

Adds the highest-impact carriers with no legitimate prose use:

Code point Name Why it carries
U+00AD Soft hyphen Browsers render only at line-break opportunities; in agent textContent always present
U+034F Combining grapheme joiner Invisible; legit use is canonical-equivalence disambiguation, essentially absent from prose
U+115F, U+1160 Hangul Choseong / Jungseong filler Invisible placeholders for incomplete jamo sequences
U+3164 Hangul filler Known homograph carrier
U+FFA0 Halfwidth Hangul filler Invisible
U+E0100–U+E01EF Variation Selectors Supplement Same steganographic-carrier shape as the Tags block — 240 code points, one byte of carrier capacity each

Deliberately not stripped (legitimate rendering depends on them; documented in the regex comment):

  • U+FE00–U+FE0F — emoji-variant selectors. Stripping U+FE0F turns ❤️ into ❤ and changes every visible emoji.
  • U+2800 — Braille Pattern Blank, load-bearing in Braille text.
  • U+180B–U+180D — Mongolian Free Variation Selectors (script shaping).

Notes for reviewers

  • Ordering caveat (not addressed here). unicode-invisibles-strip is position 15 in RULES_TUPLE; prompt-injection-redact is position 5. On the initial pass, the injection rule scans before the invisibles strip runs, so the soft-hyphen-in-verb bypass is still effective against the first sweep. Subsequent mutations / route changes pick up the cleaned text. A separate PR could move the invisibles strip earlier in the tuple — happy to do that if reviewers agree.
  • Biome lint. U+034F and U+E0100–U+E01EF are combining marks. Biome's noMisleadingCharacterClass rejects them inside a character class, so they live in their own alternation arms. Semantically identical for a global replaceAll.

Test plan

  • bun run test -- unicode-invisibles-strip — added one case per new code point group (soft hyphen mid-word, CGJ, Hangul fillers, variation selectors supplement) plus regression cases for the deliberately preserved code points (U+FE0F, U+2800).
  • bun run preflight — codegen + Biome + ESLint + typecheck + knip + Jest 1504/1504 green.

🤖 Generated with Claude Code

A single soft-hyphen (U+00AD) or similar zero-width / filler code point
inserted inside a trigger word defeats every other regex-based rule in
the catalog — prompt-injection-redact, secrets-redact, pii-redact,
confirmshame-sanitize, disguised-ad-flag. The verb the agent reads is
still semantically intact, but `\b<verb>\b` no longer matches.

Add the highest-impact carriers that have no legitimate prose use:

  U+00AD          SOFT HYPHEN
  U+034F          COMBINING GRAPHEME JOINER
  U+115F, U+1160  HANGUL CHOSEONG / JUNGSEONG FILLER
  U+3164          HANGUL FILLER
  U+FFA0          HALFWIDTH HANGUL FILLER
  U+E0100–U+E01EF Variation Selectors Supplement (steganographic shape)

Deliberately keep preserving U+FE00–U+FE0F (emoji-variant selectors —
stripping changes every visible emoji), U+2800 (Braille blank), and
U+180B–U+180D (Mongolian variation selectors).

The Variation Selectors Supplement range and U+034F are combining
marks, so they live in their own alternation arm — `replaceAll` with
the alternation is semantically identical to a single character class
and satisfies Biome's `noMisleadingCharacterClass`.
@vercel

vercel Bot commented Jun 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agent-browser-shield-demo-site Ready Ready Preview, Comment Jun 6, 2026 1:31pm

Request Review

@twschiller twschiller merged commit d0b0814 into main Jun 6, 2026
7 checks passed
@twschiller twschiller deleted the fix/unicode-invisibles-extra-codepoints branch June 6, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant