Skip to content

fix(core): invisible format chars U+206A-U+206F pass both Unicode sanitizer pipelines #3823

Description

@0xMudit

What happened

Six invisible Unicode format characters — U+206A–U+206F (INHIBIT/ACTIVATE SYMMETRIC SWAPPING, INHIBIT/ACTIVATE ARABIC FORM SHAPING, NATIONAL/NOMINAL DIGIT SHAPES) — pass through both sanitizer regexes in packages/core/src/text-sanitize.ts:

  • BIDI_FORMAT_REGEX (line 60) covers U+2066–2069 but skips its immediate neighbors U+206A–206F
  • ZERO_WIDTH_REGEX (line 72) covers U+2060–2064 but also skips U+206A–206F

All six are category Cf — invisible, zero-width, deprecated bidi-related formatting characters, squarely in the threat family these classes exist to strip. They are not whitespace, so the \s+ collapse doesn't remove them either. Live-reproduced with the exact pipeline from sanitizeUnicodeText:

input:  "alice\u206Abob"
output: "alice\u206Abob"   (invisible char survives)

Two names differing only by U+206A render identically but compare unequal. Session names, foreign titles, ids rendered verbatim, and digest payloads all share these classes ("single source of truth", per the file's own comments), so the gap is systemic. The foreign id guard FOREIGN_UNSAFE_CHARS (packages/core/src/foreign-session.ts:156) has the same gap.

No test covers U+206A–206F, so this looks like unintentional drift rather than policy.

How to reproduce

normalizeUserSessionName("alice\u206Abob"){ ok: true, value: "alice\u206Abob" } — an invisible character persists; the same string also passes isSafeForeignId.

Suggested fix

Add \u206A-\u206F to BIDI_FORMAT_REGEX (space replacement keeps word separation consistent with the other bidi controls) and to FOREIGN_UNSAFE_CHARS. A follow-up class decision could also consider variation selectors (U+FE00–FE0F) and tag characters (U+E0000–E007F), both known invisible-content vectors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions