CLAUDE LABEN
RELEASE — Claude Code v2.1.246 が8月26日に公開されました。Bash の allow ルールでサブコマンドの前にワイルドカードを置いた書き方に、起動時警告が出ますPERMISSIONS — /permissions に Auto モードタブが加わりました。既定が auto になった後、どの操作が自動で通りどこで止まるかを一箇所で確認できますMEMORY — 長い対話セッションでメモリが際限なく増える問題が修正されました。サブエージェントのツール結果が、直近の表示ウィンドウを外れた時点で解放されますMCP — headless とリモートのセッションで、受信メッセージに割り込まれたツール呼び出しが「完了・出力なし」ではなく明示的な interrupted エラーとして報告されますRUNNER — claude self-hosted-runner に --proxy-authorization-command と --proxy-authorization-file が追加されました。接続ごとに認証ヘッダを発行する egress プロキシ向けですLIMITS — 週次上限50%増の延長は8月31日までです。Pro・Max・Team とシート課金の Enterprise が対象で、残り4日となりましたRELEASE — Claude Code v2.1.246 が8月26日に公開されました。Bash の allow ルールでサブコマンドの前にワイルドカードを置いた書き方に、起動時警告が出ますPERMISSIONS — /permissions に Auto モードタブが加わりました。既定が auto になった後、どの操作が自動で通りどこで止まるかを一箇所で確認できますMEMORY — 長い対話セッションでメモリが際限なく増える問題が修正されました。サブエージェントのツール結果が、直近の表示ウィンドウを外れた時点で解放されますMCP — headless とリモートのセッションで、受信メッセージに割り込まれたツール呼び出しが「完了・出力なし」ではなく明示的な interrupted エラーとして報告されますRUNNER — claude self-hosted-runner に --proxy-authorization-command と --proxy-authorization-file が追加されました。接続ごとに認証ヘッダを発行する egress プロキシ向けですLIMITS — 週次上限50%増の延長は8月31日までです。Pro・Max・Team とシート課金の Enterprise が対象で、残り4日となりました
記事一覧/Claude Code
Claude Code/2026-08-28初級

名前に混ざった見えない文字を、プラグインを入れる前に洗い出す小さなスクリプト

プラグインやスキルの名前に不可視文字や制御文字が混ざっていても、ターミナルの一覧では見分けがつきません。実際に6つの紛らわしい名前を並べて ls の出力を比べ、導入前に走らせる点検スクリプトと、その点検が拾えない範囲までを整理しました。

claude-code131plugin3security10unicodemarketplace

同じ名前に見えるディレクトリを6つ作って ls に流したとき、私は自分の目をあまり信用しなくなりました。並んだ6行のうち、本当に claude-helper だったのは1行だけです。残りの5行は、幅も文字数もほぼ同じに見えるのに、中身のバイト列が違っていました。

きっかけは 8月26日にリリースされた Claude Code v2.1.247 です。プラグインマーケットプレイスに関する変更として、制御文字や不可視文字を含む名前を拒否するようになったと Claude Code の changelog に書かれていました。読んだときは地味な項目だと思ったのですが、では自分の環境ではどうやって確かめるのか、という問いには答えられませんでした。手を動かして確かめたので、その過程を残しておきます。

個人開発で使うプラグインやスキルは、たいてい自分ひとりで入れて自分ひとりで使います。レビューしてくれる同僚がいない環境ほど、目視以外の確認手段を1つ持っておく価値があると考えています。

一覧では6つの名前がほとんど区別できませんでした

まず、紛らわしい名前を意図的に6つ作りました。すべて私が検証のために自分で作ったもので、どこかから拾ってきた実物ではありません。

種類混入している文字文字数UTF-8 バイト数
素の名前なし1313
ゼロ幅スペースU+200B1315
ゼロ幅接合子U+200D1416
右横書きオーバーライドU+202E / U+202C1822
キリル文字の aU+04301314
ソフトハイフンU+00AD1314

注目していただきたいのは、ゼロ幅スペース入りの名前が素の名前と同じ13文字である点です。文字数を数えても差が出ません。差が出るのはバイト数だけで、13 バイトに対して 15 バイトあります。

ls の出力はこうなりました。行の順序は環境によって変わりますが、見た目の情報量はこれで全部です。

claude-helper
claude-hel[U+200D]per
claude-[U+202E]resu-daer[U+202C]
claude[U+00AD]helper
claude[U+200B]helper
clаude-helper

角括弧で囲んだ部分は、この記事のために私が入れた印です。実際のターミナルには何も表示されません。つまり本物の画面では、6行が縦にほとんど同じ形で並ぶだけです。記事に貼るときですら印を足さないと伝わらない、という事実そのものが、この問題の性質をよく表していると思います。

ここから元の名前を復元するのは、画面を眺めているだけでは無理です。私も無理でした。ところが同じ一覧を cat -v に通すと、状況が一変します。

$ ls -A d | cat -v
claude-helper
claude-helM-bM-^@M-^Mper
claude-M-bM-^@M-.resu-daerM-bM-^@M-,
claudeM-BM--helper
claudeM-bM-^@M-^Khelper
clM-PM-0ude-helper

M-bM-^@M-^K は U+200B の UTF-8 表現(E2 80 8B)です。cat -v は非表示文字をこの記法に置き換えるので、目で見えない差分がそのまま行に現れます。ターミナルで怪しい名前に出くわしたとき、最初に通すコマンドとして覚えておくと便利です。

v2.1.247 が塞いだ範囲と、手元に残る仕事

changelog に書かれている内容を、私なりに整理するとこうなります。

  • マーケットプレイス側で、制御文字や不可視文字を含む名前が拒否されるようになりました
  • /pluginclaude plugin の出力に含まれるマーケットプレイス由来のテキストがエスケープされるようになりました
  • レンダリングされた Markdown のハイパーリンクのうち、ネットワークパスやオートマウンタパスを指すもの、制御文字を含むもの、不可視文字で始まるものはプレーンテキストとして表示されます

つまり、名前そのものと、その名前が画面に表示される経路の両方が塞がれた形です。よくできた対処だと思います。

ただ、これは Claude Code が読み込む段階での防御です。手元のディスクに置かれたディレクトリ名や、自分で書いた設定ファイル、GitHub から git clone してきたリポジトリの中身までを見てくれるわけではありません。私が確かめたかったのはそちらでした。

導入前に走らせる、2つの点検関数

用意したのは短いシェル関数です。.bashrc.zshrc に貼っておいて、新しいプラグインやスキルを入れた直後に走らせています。

# 制御文字・不可視文字を含む名前を検出する
scan_names() {
  local dir="${1:?usage: scan_names <dir>}"
  local names hits
  names=$(cd "$dir" && ls -A) || return 2
  hits=$(printf '%s\n' "$names" \
    | grep -nP '[\x00-\x1F\x{00AD}\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{206F}\x{FEFF}]')
  if [ -n "$hits" ]; then
    printf '%s\n' "$hits" | cat -v
    echo "NG: 不可視文字または制御文字を含む名前が $(printf '%s\n' "$hits" | wc -l) 件あります"
    return 1
  fi
  echo "OK: 不可視文字・制御文字は見つかりませんでした"
}

対象は、制御文字(U+0000〜U+001F)、ソフトハイフン(U+00AD)、ゼロ幅文字と方向制御文字(U+200B〜U+200F、U+202A〜U+202E)、一般句読点の書式文字(U+2060〜U+206F)、そして BOM(U+FEFF)です。grep -P\x{...} 記法は PCRE のもので、GNU grep が --perl-regexp 付きでビルドされている必要があります。macOS 標準の grep では使えないので、brew install grep で入れた ggrep に置き換えるか、後述の Python 版を使ってください。

先ほどの6件に当てた結果です。

$ scan_names d
2:claude-helM-bM-^@M-^Mper
3:claude-M-bM-^@M-.resu-daerM-bM-^@M-,
4:claudeM-BM--helper
5:claudeM-bM-^@M-^Khelper
NG: 不可視文字または制御文字を含む名前が 4 件あります
$ echo $?
1

6件のうち4件を拾いました。素の名前が通るのは正しい挙動です。問題は、もう1件が素通りしていることです。

キリル文字の a は、この点検では拾えません

拾えなかったのは clаude-helper です。3文字目の а がラテン文字の a(U+0061)ではなくキリル文字の а(U+0430)になっています。これは不可視文字でも制御文字でもなく、独立した1つの表示可能な文字なので、先ほどのパターンには一致しません。

$ python3 -c "
a='claude-helper'; b='clаude-helper'
print('文字列として一致:', a == b)
import unicodedata
print('NFKC 正規化後に一致:', unicodedata.normalize('NFKC',a) == unicodedata.normalize('NFKC',b))
"
文字列として一致: False
NFKC 正規化後に一致: False

Unicode 正規化をかけても同一にはなりません。NFKC は互換文字を畳み込む正規化ですが、キリル文字とラテン文字は別の文字として設計されているので、当然といえば当然です。混同されやすい文字を網羅的に潰そうとすると、Unicode の混同可能文字表を持ち込む話になり、個人の点検スクリプトとしては重くなります。

そこで私はこの点検の線を、もっと手前に引き直すことにしました。プラグインやスキルの名前は印字可能な ASCII だけで書かれているはず、という前提を置いて、そこから外れたものを一律で報告します。

# 印字可能 ASCII 以外を含む名前を検出する(ホモグリフを含めて拾える)
scan_ascii_only() {
  local dir="${1:?usage: scan_ascii_only <dir>}"
  local hits
  hits=$(cd "$dir" && ls -A | LC_ALL=C grep -n '[^ -~]')
  if [ -n "$hits" ]; then
    printf '%s\n' "$hits" | cat -v
    echo "NG: ASCII 以外の文字を含む名前が $(printf '%s\n' "$hits" | wc -l) 件あります"
    return 1
  fi
  echo "OK: すべて印字可能な ASCII の範囲でした"
}

[^ -~] は、半角スペース(0x20)からチルダ(0x7E)までの範囲に入らない文字、という意味です。LC_ALL=C を付けているのは、ロケールによって文字クラスの解釈が変わるのを避けるためです。

$ scan_ascii_only d
2:claude-helM-bM-^@M-^Mper
3:claude-M-bM-^@M-.resu-daerM-bM-^@M-,
4:claudeM-BM--helper
5:claudeM-bM-^@M-^Khelper
6:clM-PM-0ude-helper
NG: ASCII 以外の文字を含む名前が 5 件あります

今度は5件すべてを拾いました。日本語のディレクトリ名を混ぜている環境では誤検知が増えますが、プラグインやスキルの置き場に限れば、この単純さのほうが実用的だと感じています。判断を細かくするより、線を1本引いて例外を目で確認するほうが、続けられる点検になります。

手元の 906 件に当てて、0件だったこと

書いた以上は自分の環境に当てないと意味がないので、プラグインとスキルの置き場をまとめて走査しました。ディレクトリとファイルを合わせて 906 件、うち最長の名前は 43 文字でした。

結果は、不可視文字・制御文字が 0 件、ASCII 以外の文字を含む名前も 0 件です。

何も出ませんでした。記事にする材料としては拍子抜けする結果で、私自身、少し肩透かしを食らった気分になりました。それでもこの点検を残しているのは、0 件だと確認できている状態と、確認していない状態は別物だからです。前者は次に何かが増えたときに差分として現れますが、後者はいつまでも増えたことに気づけません。

もう一点、find を使う版を最初に書いたのですが、-printf は GNU findutils 固有のオプションで macOS では使えませんでした。上に載せた関数が ls -A を使っているのはそのためです。手元で動いたコードをそのまま配るときに、いちばん踏みやすい種類の段差だと思っています。

次に試すこと

まず、自分のプラグインとスキルの置き場に scan_ascii_only を1回だけ当ててみてください。0件なら、その事実を控えておけば十分です。1件でも出たら、cat -v の行を読んで、その文字が意図して入れたものかどうかを確かめる。それだけで、目視では埋まらない穴が1つ塞がります。

この点検を毎回手で走らせるのが面倒になってきたら、フックに常駐させる段階です。どのタイミングのフックに何を置くかは、Claude Code Hooks — 8種類のフックを使い分ける設計判断と落とし穴 に、8種類それぞれの向き不向きと私が踏んだ落とし穴をまとめてあります。

最後までお読みいただきありがとうございました。小さな確認が積み重なることで安心して手を動かせるようになる、という感覚を共有できていれば嬉しく思います。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Claude Code2026-06-25
サンドボックスはコードを動かせても、認証ファイルは読ませない — Claude Code の sandbox.credentials で秘密の露出面を絞る
Claude Code のサンドボックスは既定で ~/.aws/credentials やトークン環境変数を読めてしまいます。v2.1.187 で入った sandbox.credentials を使い、無人運用の秘密の露出面をOS強制で絞る設定と検証手順を実装込みで整理します。
Claude Code2026-05-12
APIキーを誤って git commit してしまった時の緊急対応手順 — Claude Code を使った履歴削除とキーローテーション
.envのAPIキーを誤ってgit commitしてしまったときの緊急対応手順です。最初の5分で行うキーのローテーション、被害範囲の確認、git履歴からの完全削除、GitHubのシークレットスキャンニングアラートの解除、.gitignore整備を含む再発防止までClaude Codeを使って実践的に解説します。
Claude Code2026-04-25
Claude Code のシークレット管理とトラスト境界設計 — エージェント時代の秘匿情報ハンドリング本番ガイド
Claude Code がシェルを掌握する時代の秘匿情報設計を、トラスト境界・注入パターン・流出防止フックの3軸で体系化。.env から MCP までの本番運用パターンと、よくある落とし穴を実装コード付きで解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →