stacklok / stacklok/toolhive

Warn on hidden/invisible Unicode characters in SKILL.md (bidi, zero-width, tag block)

Open
#6,178 1 comment 0 reactions 1 assignee View on GitHub

@fevziegeyurtsevenler is already working on this.

Since Aug 10, 2026.

Dominant language
Go
Stars
2.2k
Forks
300
Avg merge
1d 15h
Merged PRs (30d)
184

Description

Summary

Skill validation (pkg/skills/validator.go) reads the full SKILL.md bytes but
collectWarnings only checks spec compliance (comma-delimited allowed-tools,
line count). Invisible, bidirectional, and Unicode tag characters therefore pass
validation with no signal at all.

These code points render as nothing — or silently reorder surrounding text — for
a human reviewing a skill, while remaining part of the bytes an agent consumes.
That gap lets a SKILL.md carry text a reviewer cannot see. A quick grep
confirms there is currently no handling of any of this:

grep -rniE '200b|202e|zero.width|invisible|unicode|homoglyph|bidi|feff' pkg/skills/
# only unrelated comments and the lockfile graphic-char check

This complements the Sigstore signing work: signing proves who published a
skill; it does not prove the SKILL.md is free of hidden instructions.

Proposed change

Extend collectWarnings to scan content and emit a non-blocking warning
(naming the code point and byte offset) for:

  • U+200B — zero-width space
  • U+200E–200F — left-to-right / right-to-left marks
  • U+202A–202E — bidirectional embedding/override controls
  • U+2060–2064 — word joiner and invisible math operators
  • U+FEFF — zero-width no-break space (only when it is not a leading BOM at
    byte offset 0, where it is a legitimate encoding marker)
  • U+E0000–E007F — the Unicode tag block

Deliberately excluded to avoid false positives on legitimate content:

  • U+200C (ZWNJ) and U+200D (ZWJ) — structural in emoji ZWJ sequences and
    required for correct rendering in Persian, Arabic, and several Indic scripts.
  • A U+FEFF BOM at byte offset 0 — a standard UTF-8 encoding marker.

Non-blocking is deliberate: these are valid Unicode, so the check should surface
them for review, not fail installs. Behaviour stays byte-identical for content
that contains none of the flagged code points.

I'd like to work on this and have a change ready to submit.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.