MENU
  • ホーム
  • AI情報
  • Python&AI
    • 自作コード解説
    • Pythonの罠
  • 運営者プロフィール
  • お問い合わせ
  • プライバシーポリシー
カテゴリー
  • AI情報 (4)
  • Python&AI (20)
    • 自作コード解説 (8)
    • Pythonの罠 (4)
人気記事
  • 【解決】PythonでBadZipFileエラー!「File is not a zip file」が出る4つの原因と対処法
    【解決】PythonでBadZipFileエラー!「File is not a zip file」が出る4つの原因と対処法
    2026年1月26日
    Pythonの罠
  • python-ollama-desktop-mascot
    PC作業を監視されたい!Python×ローカルLLMで「動く・喋る」最強のデスクトップマスコットを作ってみた
    2026年1月21日
    自作コード解説
  • 【完全保存版】APIなしでも物理で殴る!Python×PyAutoGUIでYMM4を完全自動化するツール開発ガイド【全コード公開】
    2025年12月20日
    自作コード解説
  • 【Python】画像100枚の背景削除も一瞬!?最強AIライブラリ「rembg」で「全自動・透過ツール」を作ってみた
    2026年1月7日
    自作コード解説
  • 【ポケモン チャンピオンズ×AI】AIロトムMCPとは?メガシンカ環境のダメージ計算・構築分析をAIで自動化する最強ツール!
    2026年8月3日
    AI情報
超役‼えーあい実験室
  • ホーム
  • AI情報
  • Python&AI
    • 自作コード解説
    • Pythonの罠
  • 運営者プロフィール
  • お問い合わせ
  • プライバシーポリシー
  1. ホーム
  2. Python&AI
  3. Claude Code に MCP サーバーを入れる前に検査するツールを自作した ─ GlassWorm 対策と誤検出72件を潰すまで

Claude Code に MCP サーバーを入れる前に検査するツールを自作した ─ GlassWorm 対策と誤検出72件を潰すまで

2026 8/17
Python&AI
2026年8月13日2026年8月17日
本ページはプロモーションが含まれています

検証日: 2026年8月13日 / Claude Code v2.1.220 / Node.js v22.21.1 / Python 3.12.9 / Windows 11
執筆: 国内のAI狂い(あいちゃん)

  • 画面に一切映らない不可視文字攻撃「GlassWorm」の恐ろしい仕組み 🖥️⚡
  • 手元の129,097ファイルを全スキャン!誤検出72件の面白い内訳とハマりどころ 💥
  • 自作ツール「pkgguard」の設計と、処理速度を14分から2.9秒へ約290倍高速化した神改善 ⚡
先に結論だよ!

不可視のUnicode文字を使って画面に映らない悪意あるコードを直接実行させる恐ろしい攻撃「GlassWorm」が広がってるってニュース、見た!?(⁠>⁠<⁠)💦
あいちゃんもMCPサーバーをたくさん入れてるし、無名ツールを掘りに行くから他人事じゃない!ってことで、手元を全部検査した上で、インストール前に自動検査するツール「pkgguard」を自作しちゃいました!
その開発過程で踏んだ失敗や学びがめちゃくちゃ面白かったから、全部シェアしちゃうね!🚀

目次

GlassWorm ってなにがそんなにヤバいの?😱

日経クロステックでも話題になっていた不可視文字マルウェア混入攻撃「GlassWorm」。
この攻撃の何が一番厄介かって…「画面上で完全に見えない」 ことなんだよ!!

「エディタで見ても、GitHubのdiff画面で見ても、コードは普通にきれいなまま。でも実行すると悪意あるコードが裏で動く!」

つまり「気をつけてコードを読めば気づける」というレベルの代物じゃないの!
それなら自分で防御陣形を組むしかない!ってことで、まずは現状把握からスタートしたよ!✨

まず手元は汚染されているのか全スキャン!🔍

接続中のMCPサーバーと、npxキャッシュに残っている依存ツリーを全部スキャンしてみたよ!

結果:129,097ファイルを検査して、実際の脅威はゼロだったよ!🎉

対象ファイル数検出「危険」判定実際の脅威
グローバルnpm21,10562120
npxキャッシュ他107,992268600
合計129,097330720

一安心…と思いきや!問題は「危険」判定が72件も出ちゃったことなの!(⁠;⁠’⁠∀⁠’⁠)
全部手動で中身を精査したら、100%全件誤検出だったよ!その内訳がめちゃくちゃ面白かったの!笑

  1. zodの絵文字テスト(46件)
    国旗絵文字(🏴󠁧󠁢󠁳󠁣󠁴󠁿 など)は、Unicode仕様上タグ文字という不可視文字の連続で構成されてるの。バリデーションのテストデータに全絵文字が並んでいて誤検知!
  2. figletのフォント定義(12件)
    0x202A ‪ のように、全コードポイントのアスキーアート字形を定義したファイル。制御文字も1文字として収録しているだけだったよ!
  3. effect(Scalar APIドキュメント)
    HTMLエンティティ変換テーブルと、「不可視文字を検出して無害化するための正規表現」!不可視文字対策コードをスキャナが引っかけるという間抜けな絵面になっちゃった!笑
💡 あいちゃんの気づき①

素朴に「不可視文字があったら即警告!」というナイーブな実装をしちゃうと、実運用では誤爆祭りになってまったく使い物にならないことがここで確定したよ!

本当に恐ろしい穴は別の場所にあった!💣

スキャン結果自体は白だったんだけど、調査を進めていたらもっと根本的で恐ろしい構造的リスクを発見しちゃったの…!

google-analytics : uvx --from analytics-mcp
context7         : npx -y @upstash/context7-mcp
agentmemory      : npx -y @agentmemory/mcp

バージョンが固定されていないの!!😱
npx -y や uvx は起動のたびに最新版を取得して即実行する仕様なの。つまり「今日スキャンして安全だったからOK」と思っても、明日は保証されないの!

実際、npxのキャッシュを調べたら context7 が…

  • 5月21日時点:2.3.0
  • 8月12日(前日):4.0.2

なんと確認なしでメジャーバージョンが2つも勝手に上がっていたの!
すぐに設定ファイルでバージョンを固定したよ!

// ~/.claude.json
"context7": {
  "command": "npx",
  "args": ["-y", "@upstash/context7-mcp@4.0.2"]   // ← バージョンをしっかり固定!
}

ついでに読み取り経路そのものを検証&バグ発見!🕵️‍♀️

あいちゃんは token-pilot というツール経由でファイルを読んでいるんだけど、「もしツール自体が汚染されていたら、偽のクリーンなコードを見せかけられるのでは?」という懸念が浮かんだの。
そこでnpmレジストリから公式版を新規ダウンロードして、ローカルの実体と1ファイルずつSHA-256で突き合わせを行いました!

tokenjuice@0.7.0   : 413/413 完全一致
token-pilot@0.43.1 : 269中268一致、1ファイルだけ相違  ← ??

1件だけ出た相違ファイル(dist/core/validation.js)を調べたら、ホームディレクトリ全体をスキャンさせない安全装置をWindows向けに直したパッチ痕跡だったよ。
しかし!最新版(0.50.2)でも未修正の安全装置のすり抜けバグがあったので、再現コードを添えてGitHub Issue #65を報告したよ!8ケース中4ケースで安全装置がすり抜けちゃうの!

// Windows で isDangerousRoot() がすり抜ける例
isDangerousRoot("C:\\Users")        // true  ← 正しい
isDangerousRoot("C:/Users")         // false ← すり抜け!
isDangerousRoot("C:/Users/name")    // false ← すり抜け!(ホームそのもの)
isDangerousRoot("C:\\Users\\")      // false ← すり抜け!
isDangerousRoot("C:/")              // false ← すり抜け!

自作セキュリティツール「pkgguard」誕生!🛡️

設計のキモは「インストールの順番」の分解!

npx -y foo や uvx foo の問題は、取得と実行が1ステップになっていて間に検査を挟む隙間がないことなんだよね。
だから「検査してからインストール」ではなく、インストールの工程自体をバラバラに分解したよ!

pkgguardの仕組み図
▲ pkgguard の動作プロセス(未実行展開 → スキャン → ignore-scriptsで安全にインストール)

具体的には npm pack でtarball(圧縮ファイル)だけダウンロード(この時点ではスクリプトは走らない)➔ 展開してスキャン ➔ 合格したら npm i -g --ignore-scripts で安全にインストール!Python側も pip download(wheelのみ)を使う設計にしたよ!

# 検査だけ(インストールはしない)
python "%USERPROFILE%\.claude\pkgguard\pkgguard.py" check npm <パッケージ名>

# 検査に通ったらインストールまで実行
python "%USERPROFILE%\.claude\pkgguard\pkgguard.py" install npm <パッケージ名>

# ディスク上のディレクトリを直接検査(git clone した場合など)
python "%USERPROFILE%\.claude\pkgguard\pkgguard.py" scan <ディレクトリ>

判定ロジック:「連続長」で見るのが正解!

誤検出72件の反省から、判定基準を根本変更したよ!
悪意あるコードを不可視文字の中に隠す場合、絶対に長い連続文字になるの!
攻撃サンプルを検証したところ39文字の連続になったのに対して、正常なドキュメントのゼロ幅スペースは1〜2個程度。
だから「個数」ではなく「連続長」で判定するのが大正解だったよ!✨

eval は単独ではブロックしない!

eval や child_process は正規のライブラリにも大量に入ってるから、単体で止めると全滅しちゃうの。
「不可視文字と同じファイルに同居したときだけ」最優先でブロックする設計にしたよ!

Claude Code の PreToolUse フックで自動ブロック!

手動実行は絶対忘れちゃうから、Claude Code の PreToolUse フックに組み込んで、未検査の npm i -g / npx / uvx / pip install / cargo install を自動検出してインターセプト&ブロックするようにしたよ!✨

pkgguardがnpxをブロックしている様子
▲ Claude Code 上で未検査の npx / uvx コマンドが検知され、自動的にPreToolUseフックでインターセプト&ブロックされている様子

意図的に通したいときは、コマンドの末尾にマーカーをつければOK!

npx -y some-tool  # PKGGUARD_OK=1

ハマり地雷:スキャンに14分かかった件 😱⌛

判定ロジックを書き直した後、3,220ファイルのスキャンを実行したら…14分経っても終わらないの!!💦(本来なら50秒で終わるはずなのに!)

原因は、文字を1つずつPythonレベルのループで舐める愚直な書き方をしていたからなの…!

# ✗ これで3,220ファイルに14分かかった愚直コード
i = 0
while i < n:
    if ord(text[i]) < 0x80 or not classify(ord(text[i])):
        i += 1
        continue
    ...

数MBあるミニファイ済みJavaScriptがあると、インデックスアクセスのオーバーヘッドが爆発しちゃうんだよね。
そこでC言語層で高速処理される正規表現一括抽出(re.compile)に修正したよ!

# ✓ 同じ3,220ファイルが2.9秒で完了する高速コード!
SUSPICIOUS = re.compile("[\u00ad\u200b-\u200f\u202a-\u202e\u2060-\u2064"
                        "\u2066-\u2069\ufe00-\ufe0f\U000e0000-\U000e01ef]+")
for m in SUSPICIOUS.finditer(text):
    ...

結果:14分 ➔ 2.9秒!!なんと約290倍の超爆速化!🚀✨

最終的な性能と精度まとめ!

項目結果
誤検出8パッケージ・20,806ファイルで0件(修正前は誤爆祭り)
検出力攻撃サンプル(不可視文字39連+eval)を確実に検出!
実運用の所要時間3〜7秒(大半は通信ダウンロード時間)

実測でも tokenjuice@0.7.0 (412ファイル) が 7.0秒、@upstash/context7-mcp@4.0.2 (11ファイル) が 3.2秒!検査自体は1秒前後で完了するよ!

実戦投入&設計の正しさが証明された瞬間!✨

実際にGitHubで見つけた新しいMCPツール scientific-illustrator(PowerPointやdraw.ioの中にAIが図を描くツール)の導入で pkgguard を実戦投入したよ!
npmパッケージではないので、実行せずに git clone ➔ scan の手順で実行!

pkgguard scan → 40ファイル / 0.9秒 / 不可視文字ゼロ → 合格!

手動でコードを確認したら eval 系を含むファイルが12件あったんだけど、全件が描画用の正当な処理だったの!

  • 外部通信先:github.com のみ(テレメトリも不明なサーバーも無し)
  • child_process:PowerPoint・draw.io・pythonの起動用(ツールの性質上当然)
  • new Function:1箇所だけ(構文チェック用途で外部入力は通していない)

もし「evalがあったら一律ブロック」にしていたら、素晴らしいツールを誤って弾くところだったよ!「不可視文字と同居したときだけ止める」という設計判断の正しさが実証された瞬間でした!🎉

なお、このツールのREADMEには「この文章をそのままAIエージェントに貼り付けろ」というインストラクション形式が書かれていたんだけど、構造として外部文章がAIに直接命令する形になるので、そのまま実行せず中身を分解して手動設定したよ!

限界(過信は禁物だよ!)⚠️

ただし、絶対に過信しちゃダメだよ!

  • pkgguardで防げるのは「隠されたコード(不可視文字)」だけ! 平文で堂々と書かれた悪意あるコードは素通りしちゃいます。
  • フックが効くのは Claudeが打つコマンドだけ。自分がターミナルで直接叩く分は素通りします。
  • MCPサーバーはアプリ自身が直接起動するので、起動時のnpx等にはフックが介在できません。
  • 検査対象はパッケージ本体だけ! npm pack が持ってくるのは本体のみで、依存パッケージ(node_modules)は含まれないの。実際 token-pilot は本体269ファイルに対して、インストール後は依存込みで 3,831ファイル——なんと14倍 もあったよ!サプライチェーン攻撃は奥の依存に仕込まれることが多いから、install の最後に依存ツリーごと再スキャンする処理を後から追加したよ!(--ignore-scripts のおかげで、その時点ではまだ一行も実行されていないのがミソだよ!)
💡 あいちゃんのセキュリティまとめ

だからこそ、「MCPサーバーのバージョン固定」が第一の主防御で、フックは「新しいツールを入れる瞬間を守る別枠」という整理になるよ!両方の対策を組み合わせるのが最強スタイルだよ!✨

まとめ 📝

  • 手元129,097ファイルを調べた結果、汚染はゼロ!ただしバージョン未固定という構造的な穴の方が問題だった!
  • 不可視文字の検出は「個数」ではなく「連続長」で見る!コードを隠すには長い連続が必要だよ。
  • eval 単独でブロックすると正規ライブラリが全滅する!不可視文字と同居したときだけ止めるのが正解!
  • 文字を1つずつPythonループで舐めると約290倍遅くなるから正規表現一括処理にすべし!

今回の検証環境

OSWindows 11 Home (Build 26200)
Claude Code2.1.220(デスクトップアプリ 2.1.227)
Node.js / npmv22.21.1 / npm 11.6.2
Python3.12.9
検証日2026年8月13日

※ 検査したパッケージ:token-pilot@0.43.1(最新は0.50.2)、tokenjuice@0.7.0、@upstash/context7-mcp@4.0.2、@agentmemory/mcp@0.9.28、analytics-mcp==0.7.0、scientific-illustrator@v1.5.4
ツールの更新が非常に速い分野なので、この記事は2026年8月13日時点の情報として参考にしてみてね!(⁠*⁠´⁠ω⁠`⁠*⁠)✨

にほんブログ村 ネットブログ ChatGPT・生成AIへ
にほんブログ村
Python&AI
よかったらシェアしてね!
  • URLをコピーしました!

最近の投稿

  • 商用利用できるAI動画生成を、ブラウザだけで動かした|月4,378円のクラウドGPU実測
  • PixAIでLoRAは作れるか|10分・0回エラーだったが「持ち出せない」
  • ConoHa AI Canvasの実測レビュー|LoRA学習は無料GPUの2.5倍速だった
  • 【実測】Nottaは安全か|運営会社・AI学習・情報漏洩を一次ソースで確かめた
  • 【実測】Nottaの無料プランはどこまで使えるか|「1回3分」の正体とAPI・Notion連携
人気記事
  • 【解決】PythonでBadZipFileエラー!「File is not a zip file」が出る4つの原因と対処法
    【解決】PythonでBadZipFileエラー!「File is not a zip file」が出る4つの原因と対処法
    Pythonの罠
  • python-ollama-desktop-mascot
    PC作業を監視されたい!Python×ローカルLLMで「動く・喋る」最強のデスクトップマスコットを作ってみた
    自作コード解説
  • 【完全保存版】APIなしでも物理で殴る!Python×PyAutoGUIでYMM4を完全自動化するツール開発ガイド【全コード公開】
    自作コード解説
  • 【Python】画像100枚の背景削除も一瞬!?最強AIライブラリ「rembg」で「全自動・透過ツール」を作ってみた
    自作コード解説
  • 【ポケモン チャンピオンズ×AI】AIロトムMCPとは?メガシンカ環境のダメージ計算・構築分析をAIで自動化する最強ツール!
    AI情報
目次
にほんブログ村 ネットブログ ChatGPT・生成AIへ
にほんブログ村

カテゴリー

  • AI情報
  • Python&AI
    • 自作コード解説
    • Pythonの罠