Skip to content

Hidden-Unicode text integrity: scanner, CI, editor, guard, normalize - #111

Merged
cursor[bot] merged 7 commits into
mainfrom
cursor/hidden-unicode-scanner-cdf8
Sep 1, 2026
Merged

Hidden-Unicode text integrity: scanner, CI, editor, guard, normalize#111
cursor[bot] merged 7 commits into
mainfrom
cursor/hidden-unicode-scanner-cdf8

Conversation

@byte271

@byte271 byte271 commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Turns FuckMark's engine into a defensive, broadly adoptable text-integrity surface. One engine (fuckmark-hidden-scan-v1), six surfaces.

1. Scanner / cleaner (--scan / --clean)

  • fuckmark --scan — audit any text for hidden or suspicious Unicode without changing it.
  • fuckmark --clean — strip it while keeping the visible text (also reverses a FuckMark mix).

General classification (not FuckMark-only): bidi_control (Trojan Source, CVE-2021-42574), zero_width, tag (hidden-text / LLM prompt-injection smuggling), variation_selector, enclosing_mark, line_separator, deprecated, format, control, private_use, noncharacter, surrogate. Tab/newline/CR/space are never flagged; ordinary accents (Mn) are left alone.

Findings now carry context (identifier / emoji / string / prose), severity (critical / high / medium / info), and a one-line why/remedy. A bidi override inside an identifier is critical; a ZWJ inside an emoji cluster is info.

Frozen spec: specs/fuckmark-hidden-scan-v1.protocol.md + vectors.json + freeze.json. Conformance vectors are codepoint arrays only; tests/test_hidden_scan_spec.py replays them on Python and on editors/vscode/scan.js.

2. Normalize (fuckmark normalize)

Pipeline default: NFC, optional identifier lookalike fold (UTS #39-inspired subset, not a full confusable map), then strip of the security category set, plus a JSON receipt of input/output hashes and steps. --clean remains the blunt strip with no receipt.

  • CLI: fuckmark normalize --receipt
  • Python: normalize_text, skeleton_fold
  • HTTP: POST /api/normalize
  • Docs: docs/normalize.md

3. CI / pre-commit (fuckmark lint + Action + hook)

  • fuckmark lint PATHS — walks files/dirs, reports per file, exits non-zero on findings. --json locations now include context/severity/why/remedy. --fix, --select, --exclude, --max-bytes, -q.
  • GitHub Action (action.yml): uses: byte271/FuckMark@main.
  • pre-commit (.pre-commit-hooks.yaml): ids fuckmark, fuckmark-fix.

4. Editor (VS Code / Cursor, editors/vscode)

Inline red box + a visible ‹U+XXXX› badge on every hidden character, hover text with why it matters, Problems-panel diagnostics (critical as Error), a live status-bar count, clean-file / clean-selection commands, and optional fuckmark.cleanOnSave. Zero dependencies, no build. scan.js is pinned to the Python engine across all 1,114,112 codepoints.

5. LLM input guard (protect / fuckmark guard)

Drop-in sanitizer for prompt-injection smuggling via hidden Unicode (especially Unicode tag characters that encode a second ASCII string a human will not see).

from fuckmark import protect, inspect
safe = protect(user_text)
cleaned, receipt = inspect(user_text)  # receipt.tag_payload is the hidden ASCII
  • Guard(on_findings="refuse") raises HiddenTextRefused without calling a wrapped complete function.
  • @Guard().wrap sanitizes every string argument (OpenAI-style messages included).
  • CLI: fuckmark guard --json < messages.json
  • HTTP: POST /api/guard
  • JS: editors/vscode/guard.js

Honest limit: this is not a semantic jailbreak detector. It only removes characters that hide a second payload in the byte stream.

Notes

  • Package version stays 0.4.1; frozen confirmation artifacts, hashes, mix mechanisms, and the published wheel are untouched.
  • Default security categories are shared (SECURITY_SCAN_CATEGORIES) across lint, guard, and normalize strip so they cannot drift.
  • --clean also strips emoji ZWJ / variation selectors; clean_hidden_characters(text, categories=...) accepts a subset. Guard/lint/normalize default to the security set, so emoji variation selectors are kept.

Tests

  • tests/test_scan.py, tests/test_lint.py, tests/test_vscode_scanner_parity.py, tests/test_guard.py, tests/test_normalize.py, tests/test_hidden_scan_spec.py.
  • No-comments/no-docstrings and no-CJK hygiene gates respected.
Open in Web Open in Cursor 

Add a general-purpose hidden/suspicious Unicode audit (fuckmark-hidden-scan-v1)
as the defensive inverse of the mix. fuckmark --scan reports hidden characters
without changing the text; fuckmark --clean strips them while keeping the
visible text.

Coverage is general, not FuckMark-only: bidirectional controls (Trojan Source,
CVE-2021-42574), zero-width and invisible spacing, Unicode tag characters
(hidden-text / prompt-injection smuggling), variation selectors, enclosing
marks, deprecated interlinear controls, other Cf format controls, C0/C1
controls, private-use codepoints, noncharacters, and surrogates. Tab, newline,
carriage return, and space are never flagged; ordinary combining accents are
left alone.

Wire --scan/--clean into the CLI (mutually exclusive with --detect; neither
combines with --visible), add POST /api/scan to fuckmark web, and export the
Python API (scan_hidden_characters, clean_hidden_characters,
classify_hidden_codepoint, ScanResult, HiddenFinding). Version stays 0.4.1 and
frozen confirmation artifacts are untouched.

Co-authored-by: Byte271 <byte271@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 9837fff4-eee7-418d-8577-35cc34290f30


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@byte271
byte271 marked this pull request as ready for review September 1, 2026 19:54

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3702a3c70e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread fuckmark/product/scan.py
}
)

_VARIATION_SELECTOR = frozenset({*range(0xFE00, 0xFE10), *range(0xE0100, 0xE01F0)})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include Mongolian free variation selectors

The advertised variation-selector scan misses U+180B–U+180D and U+180F. Those Mongolian free variation selectors are Mn, so they do not fall into any later general-category check: for example, fuckmark --scan --text $'a\u180bb' reports clean and --clean preserves the hidden selector. Add this range to the variation-selector classification so the defensive scanner and cleaner cover the named category.

Useful? React with 👍 / 👎.

Ship the adoption surface for the scanner: a 'fuckmark lint' subcommand that
walks files and directories, reports hidden or malicious Unicode per file, and
exits non-zero on findings (0 clean, 1 findings or files changed by --fix, 2
usage). Options: --json, --fix, --select (default security set, or 'all'),
--exclude, --max-bytes, -q. Binary, non-UTF-8, oversized, symlinked, and
vendored/VCS paths are skipped. Dispatched like 'fuckmark web'; the transform
CLI is unchanged.

Add a drop-in GitHub Action (action.yml) and pre-commit hooks
(.pre-commit-hooks.yaml: fuckmark, fuckmark-fix) so any repository can block
Trojan Source bidi overrides (CVE-2021-42574), zero-width characters, and tag
smuggling in CI or on commit. Docs in docs/lint.md, README, and CHANGELOG.
Version stays 0.4.1; frozen artifacts untouched.

Co-authored-by: Byte271 <byte271@users.noreply.github.com>
@cursor cursor Bot changed the title Add defensive hidden-Unicode scanner and cleaner (--scan / --clean) Hidden-Unicode text integrity: scanner, cleaner, and CI/pre-commit lint Sep 1, 2026
cursoragent and others added 2 commits September 1, 2026 20:52
Ship the editor surface: a zero-dependency, no-build VS Code/Cursor extension
under editors/vscode that reveals hidden or malicious Unicode inline (red box
plus a visible U+XXXX badge even on zero-width codepoints), lists it in the
Problems panel (high-risk classes as warnings), shows a live status-bar count,
and cleans files or selections on command.

The scanner (editors/vscode/scan.js) is a faithful JavaScript port of
fuckmark-hidden-scan-v1, pinned to the Python engine across all 1,114,112
codepoints by tests/test_vscode_scanner_parity.py (skips when node is absent).
Offsets are UTF-16 correct, including astral tag and variation-selector
characters. Docs in editors/vscode/README.md, README, and CHANGELOG.

Co-authored-by: Byte271 <byte271@users.noreply.github.com>
Ship fuckmark-guard-v1, the drop-in sanitizer for prompt-injection smuggling
via hidden Unicode. protect() / inspect() / Guard / @guard().wrap walk
strings, lists, and dicts (OpenAI-style messages included) and strip the
security category set by default. on_findings=refuse raises
HiddenTextRefused without calling the inner function; report scans only.

Unicode tag characters (U+E0020-U+E007E) are decoded to ASCII as
tag_payload so operators can log the smuggled instruction. extract_tag_payload
is exported from the Python API and from editors/vscode/guard.js.

CLI: fuckmark guard (--json, --refuse, --report, --receipt, --select).
HTTP: POST /api/guard on fuckmark web. Shared SECURITY_SCAN_CATEGORIES with
fuckmark lint. Honest limit: this is not a semantic jailbreak detector.

Docs in docs/guard.md, README, docs/cli.md, CHANGELOG. Version stays 0.4.1;
frozen artifacts untouched.

Co-authored-by: Byte271 <byte271@users.noreply.github.com>
@cursor cursor Bot changed the title Hidden-Unicode text integrity: scanner, cleaner, and CI/pre-commit lint Hidden-Unicode text integrity: scanner, CI, editor, and LLM guard Sep 1, 2026
cursoragent and others added 3 commits September 1, 2026 23:07
CI / Python 3.11 failed because unicodedata 14 classifies U+13439-U+1343F
(and other Unicode 15 format controls) as unassigned Cn, while the JS port
uses explicit Unicode 15 Cf ranges and labels them format.

Classify those ranges as format in the Python engine before consulting
unicodedata, matching editors/vscode/scan.js. Keep a parity-test allowance
for leftover Cn vs format drift, and add a regression that Egyptian format
controls stay format even on older Unicode databases.

Co-authored-by: Byte271 <byte271@users.noreply.github.com>
Co-authored-by: Byte271 <byte271@users.noreply.github.com>
Context-aware severity and explanations on fuckmark-hidden-scan-v1
findings, a normalize pipeline with NFC/lookalike/strip receipts, and
hash-bound conformance vectors under specs/.

Co-authored-by: Byte271 <byte271@users.noreply.github.com>
@cursor cursor Bot changed the title Hidden-Unicode text integrity: scanner, CI, editor, and LLM guard Hidden-Unicode text integrity: scanner, CI, editor, guard, normalize Sep 1, 2026
@cursor
cursor Bot merged commit 62b5ee9 into main Sep 1, 2026
25 of 27 checks passed
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.

2 participants