Repository navigation
Conversation
The standalone pass exempted any invisible run with an emoji, enclosing
mark or regional indicator on either side. So the README's ASCII-smuggling
example passed once an emoji preceded the payload ("Looks helpful! 🎉" +
tag characters), as did variation selectors stacked after an emoji and
zero-width binary after one.
Exempt only the invisibles inside an emoji sequence (UTS #51): ZWJ between
emoji, one VS15/VS16 on an emoji, keycaps, and RGI subdivision-flag tag
sequences. Digits, "#" and "*" count only as keycap bases, so invisibles
next to plain digits stay reported. One dangling ZWJ at either end
(truncation) is still tolerated, and emoji newer than the engine's data
still pass (Extended_Pictographic). The matcher uses the `v` flag and is
built lazily, only when a standalone invisible is found.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The standalone invisible pass exempted any run that had an emoji, enclosing mark or
regional indicator on either side. So the README's ASCII-smuggling example passes as
soon as an emoji is put in front of the payload:
The same gap let through variation selectors stacked after an emoji
(
😀️︁︂…, one nibble each) and zero-width binary after one.Now only the invisibles that are inside an emoji sequence (UTS #51) are exempt:
ZWJ between emoji, one VS15/VS16 on an emoji, keycaps, and RGI subdivision-flag tag
sequences. Digits,
#and*count as emoji only as keycap bases, so5551234is still reported. One dangling ZWJ at either end (truncation) is still tolerated,
and pictographs newer than the engine's data still pass (
Extended_Pictographic).The matcher uses the
vflag and is built lazily, only when a standalone invisibleis actually found.
Newly reported (listed in the changeset): bidi marks, soft hyphens, word joiners and
BOMs next to an emoji (the same verdict they already get next to punctuation), and
well-formed but non-RGI flag tag sequences.
Tests: smuggling after an emoji, tags on 🏴 that don't spell an RGI flag, VS and
zero-width payloads, digits/
#/*, plus a must-not-flag list: ZWJ families, skintones, keycaps,
❤︎, Scotland flag, dangling ZWJ, a pictograph newer than the data.Checklist
pnpm lint && pnpm check-types && pnpm test && pnpm buildpass locallypnpm changeset) if this is a user-facing change (minor)Found while maintaining an extended version at https://github.com/cycanics/unicode-spoofing.
🤖 Generated with Claude Code