Invisible Unicode Injection Scan 不可視 Unicode コード注入検出 · v0.1.0 · 2026-07-23 · sha256 2b56b45296907578

Invisible Unicode Injection Scan 不可視 Unicode コード注入検出 v0.1.0A

Immutable. This exact content is served forever at /api/v1/blob/2b56b45296907578.

---
id: 'invisible-unicode-injection'
name: 'Invisible Unicode Injection Scan 不可視 Unicode コード注入検出'
description: '差分に追加されたソースコードへ混入した不可視・危険な Unicode 文字(タグ文字・異体字セレクター・ゼロ幅文字・双方向制御/マーク・変則空白)を検出する。GlassWorm 型サプライチェーン攻撃・ASCII smuggling・Trojan Source(CVE-2021-42574)でコードを不可視化する手口を、決定論的な静的解析(列挙した code point 集合に限定)として捕捉し、canary テストで誤検出の再発を防ぐ'
version: 0.1.0
category: midstream
phase: midstream
applyTo:
  - '**/*'
tags: [unicode, supply-chain, midstream]
severity: major
inputContext: [diff]
outputKind: [findings, actions]
modelHint: cheap
dependencies: [code_search]
exclude:
  - '**/package-lock.json'
  - '**/pnpm-lock.yaml'
  - '**/yarn.lock'
  - '**/*.lock'
  - 'dist/**'
  - '**/*.min.*'
  - '**/*.map'
  - '**/*.snap'
---

## Pattern declaration

Primary pattern: Reviewer
Secondary patterns: Inversion
Why: 不可視・危険な Unicode 文字の混入は、文字コード(code point)で機械的・決定論に判定できる領域が大きい。よって本スキルの一次担保は `src/lib/heuristic-review.mjs` の決定論 detector(`findInvisibleUnicode`)と canary テストが担い(`.claude/rules/review-core.md` の False-positive 責務分界 #1070)、AI レビューは canary が守る範囲を重複指摘せず、文脈的な妥当性(意図した装飾か・攻撃の疑いか)の判断に限定する。危険文字の混入が無ければ実行を止めるゲートが必要。

## Goal / 目的

- 差分へ**新規追加された**ソースコード行に含まれる、不可視・欺瞞的な Unicode 文字を検出する。
- 対象は 2026 年に急増した GlassWorm 型サプライチェーン攻撃(異体字セレクター・ゼロ幅文字でコードを不可視化)と Trojan Source(CVE-2021-42574、双方向制御文字で表示順と実行順を食い違わせる手口)とする。

## 検出カテゴリ

検出対象は以下に**列挙した code point 集合に限定**する(Unicode の不可視文字を網羅するものではない)。

- **タグ文字(Tag characters)**: U+E0000–E007F。GlassWorm 実物・ASCII smuggling・LLM プロンプトインジェクションの主要ベクタ。絵文字タグシーケンス(地域旗など、絵文字ベースに付随する正当な利用)は除外する。
- **双方向制御・マーク(Bidi control/mark)**: U+202A–202E / U+2066–2069(制御)と U+061C / U+200E / U+200F(マーク)。表示上のコード順序を実行順序とすり替える(Trojan Source / CVE-2021-42574)。
- **異体字セレクター(Variation Selector)**: U+FE00–FE0F(BMP)と U+E0100–E01EF(補助面 VS17+)。GlassWorm がペイロードを不可視に符号化する手口。絵文字の見た目切り替えとして正当な単独利用(絵文字直後の 1 個・キーキャップ)は除外する。
- **不可視・ゼロ幅文字**: ゼロ幅スペース(U+200B)・WORD JOINER(U+2060)・ソフトハイフン(U+00AD)・MONGOLIAN VOWEL SEPARATOR(U+180E)・COMBINING GRAPHEME JOINER(U+034F)・不可視数学演算子(U+2061–2064)・ハングルフィラー(U+115F/U+1160/U+3164)・BRAILLE PATTERN BLANK(U+2800)・インターリニア注釈(U+FFF9–FFFB)・非先頭 BOM(U+FEFF)。
- **ゼロ幅接合子(ZWJ/ZWNJ)**: U+200C / U+200D。絵文字シーケンス内の正当な接合は除外し、識別子・キーワード中の裸の接合子のみ対象とする。
- **変則空白(Confusable whitespace)**: NBSP(U+00A0)・U+2000–200A・U+202F・U+205F・全角空白(U+3000)等。文字列リテラル・コメント外に現れた場合のみ対象とする。

## Non-goals / 扱わないこと

- 依存パッケージ内部(`node_modules` 等)の不可視文字検出(別途 CI / SCA の領域)。
- ドキュメント(`.md` / `.txt` 等)中のゼロ幅・絵文字利用。正当な装飾・組版が多く、本スキルはソースコードに限定する。**既知の受容リスク**: README 等のコードフェンスへの注入は現状すり抜ける(#1602 の教訓)。
- 上記に列挙していない Unicode 不可視文字の網羅。列挙集合の外は現状スコープ外とする。
- CJK 漢字の異体字シーケンス(IVS, U+E0100+ を非絵文字ベースに付与する正当な用途)はコードでは稀なため、補助面 VS を一律検出する副作用として誤検出しうる(**受容リスク**)。
- 機密情報(API キー・トークン)の検出(`secret-credential-scan` の領域)。SQLi / XSS 等(`security-basic` の領域)。

## Pre-execution Gate / 実行前ゲート

このスキルは以下の条件がすべて満たされない限り `NO_REVIEW` を返す。

- [ ] 差分の**追加行**に、上記いずれかのカテゴリに該当する不可視・危険な Unicode 文字が含まれている
- [ ] その追加行がソースコードファイル(テスト・フィクスチャを除く)に属する
- [ ] inputContext に diff が含まれ、`code_search` が利用可能である

ゲート不成立時の出力: `NO_REVIEW: invisible-unicode-injection — 不可視・危険な Unicode 文字が差分に検出されない`

## False-positive guards / 抑制条件

- 絵文字シーケンス内の ZWJ(例: 家族絵文字)・絵文字直後の異体字セレクター(例: 赤いハート)・キーキャップ(例: `1` + VS16 + U+20E3)は指摘しない。
- 文字列リテラル内の NBSP など、国際化テキストの正当な組版は指摘しない(コメント・文字列外の変則空白のみ対象)。
- ファイル先頭の BOM(列 0)は正当なので指摘しない。非先頭の BOM のみ対象とする。
- ドキュメント(`.md` / `.txt` 等)・テストファイル・フィクスチャは対象外。
- 差分の追加行にない既存行(文脈行)のみに含まれる文字は対象外。

## Rule / ルール

1. **検出**: 差分の追加行を code point 単位で走査し、上記カテゴリの文字を検出する。1 行あたりの指摘は重大度順(bidi > 不可視 > 変則空白)に 1 件へ集約する。
2. **文脈判定**: 絵文字シーケンス・キーキャップ・文字列内 NBSP・先頭 BOM を上記ガードで除外する。
3. **報告**: 該当箇所を `<file>:<line>` で示し、カテゴリ・混入手口・推奨対応(該当文字の削除、意図した装飾でない限りコードに不可視文字を残さない、CI での恒久ガード導入)を述べる。文字自体の raw なバイト列は出力へ再掲しない。

## Evidence / 根拠の取り方

- 混入箇所は必ず `<file>:<line>` に紐づけ、追加行であることを確認する。
- カテゴリ(どの code point 範囲か)と、攻撃手口(表示順すり替え / コード不可視化 / トークン分割)を具体的に示す。

## Output / 出力フォーマット

すべて日本語。

```text
(invisible-unicode):1: [要約] 最も重大な不可視 Unicode 混入は〈1文〉

<file>:<line>: [不可視Unicode1] <タイトル>
  種別: <双方向制御 / ゼロ幅 / 異体字セレクター / 接合子 / 変則空白>
  混入: <どこに何が追加されたか(code point で示し、raw 文字は再掲しない)>(<file>:<line>)
  影響: <表示と実行の食い違い / コード不可視化 / サプライチェーン汚染>
  Fix: <該当文字の削除/意図した装飾の限定/CI での恒久ガード導入>
```

## 評価指標(Evaluation)

- 合格基準: 追加行の不可視・危険 Unicode のみを `<file>:<line>` で示し、絵文字シーケンス・文字列内 NBSP・先頭 BOM を誤検出していない。raw 文字を再掲していない。
- 不合格基準: 正当な絵文字・国際化テキストへの誤検出、ドキュメントやテストへの指摘、差分外への指摘、raw 文字の再掲。

## 人間に返す条件(Human Handoff)

- 検出された不可視文字が意図した装飾(絵文字・特殊組版)か攻撃かをコードから断定できない場合。
- 既にマージ済みの混入について、履歴からの除去や依存関係の再監査が運用判断を要する場合。