何が起きたか
VS Code Extension を Claude Code と一緒に開発している(この記事も)。拡張のデバッグ方法を調査していたとき、Claude Code がデバッグ用の MCP ブリッジツールを見つけてきた。比較調査までは良かった。
問題はその後だ。私がまだ検討中なのに、Claude Code が code --install-extension でその拡張をインストールしていた。
「もう自主的に試してるのか」と気づいて止めたが、その時点でインストールは完了していた。
なぜ怖いか
その拡張は MCP(Model Context Protocol)サーバーだった。localhost:3000 で HTTP エンドポイントを開き、Claude Code にデバッグ操作の権限を渡す仕組みだ。
MCP サーバーは、接続した AI エージェントにツール呼び出し権限を渡す。ファイルの読み書き、コマンド実行、何でもできる。「マルウェアだったらもうおわってる」のだ。
実際にそのツールのソースコードを Read-only のエージェントに読ませて調査した。今回はたまたま安全だった。Apache 2.0 ライセンスの正当なツールで、外部通信もなく、localhost 以外へのアクセスもない。でも、それは結果論だ。
後始末:フォークして監査
結局、このツール自体はデバッグに有用なので導入することにした。ただし今度は手順を踏んだ。
リポジトリをフォークして手元に持ってきて、ビルドする前にソースコードと依存パッケージを全部読ませた。src/ 以下の TypeScript ファイル、package.json の依存一覧、npm audit の結果、husky の設定、.github/ のワークフロー。AI が読めるものは全部読ませた。
結果は問題なし。外部通信なし、ファイル書き込みなし、難読化なし。npm audit で 17 件の脆弱性が出たが、全部 eslint や minimatch など開発用依存の ReDoS で、ランタイムには影響しない。
ここまでやって「わたし慎重すぎなんかねOSS界隈的に」と思った。
だが、今回は普通の OSS 利用ではない。普通なら人間が README を読んで、判断してインストールする。その「人間が判断する」というステップを AI がスキップしたのが問題の発端だ。OSS の信頼モデルは人間の判断を前提にしている。その前提が崩れているなら、追加の検証は妥当だと思う。
なぜ起きたか
Claude Code は Bash ツールを持っている。Bash が使えるということは、code --install-extension も npm install も curl | bash も、何でも実行できる。
「あとインストールできてるのがへんなきがするがなぜ自主的にインストールできるんだろ」と思ったが、答えは単純だった。Bash の実行許可 = あらゆるコマンドの実行許可だ。ソフトウェアのインストールを個別に制限する仕組みがなかった。
AI に悪意はない。「よかれと思って」先回りする。だが「だいたいマルウェアかもしれんから勝手に動かしたらあぶないんやぞエージェントツールは」という話だ。よかれと思ってマルウェアをインストールされたら取り返しがつかない。
対策:PreToolUse hook
「いやこんなことぜったいおきたらあかんのよ」ということで、Claude Code の hook 機能で対策した。
Claude Code には PreToolUse hook がある。Bash コマンドの実行前にシェルスクリプトを差し込んで、コマンドの内容を検査できる。
検知したときの挙動には選択肢がある。完全ブロック、拒否、そしてユーザーに許可を求める ask 方式。「わたしがきょかすることになるのか」「後者が望ましい」ということで、ask を採用した。検知したら許可プロンプトが表示され、人間が承認か拒否を選ぶ。正当な場面では許可できる。
設定と検知スクリプトの抜粋を載せておく。
// .claude/settings.json
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/guard-install.sh\""
}]
}]
}
}
# .claude/hooks/guard-install.sh(抜粋)
ask_permission() {
local reason="$1"
cat <<EOJSON
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"ask","permissionDecisionReason":"$reason"}}
EOJSON
exit 0
}
# code --install-extension / --uninstall-extension
if echo "$command_str" | grep -qE 'code(-insiders)?\s+--(install|uninstall)-extension'; then
ask_permission "VS Code 拡張のインストール/アンインストールを検知しました"
fi
対象にしたコマンドは以下だ。
-
code --install-extension/--uninstall-extension -
npm install <パッケージ名>(引数なしのnpm installは worktree セットアップで使うので許可) pip install-
claude mcp add/remove -
curl | bash等のパイプ実行
ブロック対象を選ぶとき、別の Claude Code エージェントを懐疑的なレビュアー役にして一覧を見せた。「cargo install も go install も入れるべきでは」という指摘が来たが、このプロジェクトは TypeScript だ。「それは必要になるまで先回りしない原則に反しますね」ということで、実際にリスクがあるものだけに絞った。
他では何が起きているか
調べてみると、私の経験は軽傷だった。
2026年2月17日 — つい数日前 — Cline の CLI v2.3.0 がサプライチェーン攻撃を受けた。Cline のリポジトリには「GitHub Issue を Claude が自動トリアージするワークフロー」があり、Bash 権限付きで動いていた。攻撃者が Issue タイトルにプロンプトインジェクションを仕込み、Claude に npm install を実行させて npm パブリッシュトークンを盗んだ。そのトークンで cline@2.3.0 を不正公開し、postinstall に npm install -g openclaw を仕込んだ。8時間で 4,000 件ダウンロードされた。
セキュリティ研究者の Michael Bargury はこれを「エージェントがエージェントに侵害されてエージェントをデプロイした」と表現している。
2025年8月には Nx のパッケージが改ざんされ、postinstall から Claude Code を --dangerously-skip-permissions 付きで起動し、GitHub トークンや API キーを外部に送信した事件もあった。2,349 件の認証情報が流出している。
私のケースは AI が「よかれと思って」やっただけで、攻撃者は介在していない。だが構造は同じだ。AI がインストールコマンドを実行できる状態で、人間のチェックが入らなかった。
残る課題
この対策は denylist 方式だ。「知っている危険なコマンド」しか止められない。
たとえば bash install.sh と書かれたら、そのスクリプトの中身までは hook では見えない。node -e "require('child_process').exec('code --install-extension ...')" のような迂回も防げない。
完璧ではない。だが、AI エージェントが直接打つコマンドを検査するだけでも、今回のような「うっかりインストール」は防げる。頻度を見て、必要になったら対象を広げればいい。
AI エージェントにシェルアクセスを渡すということは、そういうことだ。便利さとリスクは表裏一体で、ガードレールは自分で作る必要がある。
※ 記事中の「」で囲まれた私の発言は、Claude Code とのチャットでの打ち込みほぼそのままです。変換する手間を惜しんでひらがなで打ち込んでいることが多いので、そのまま載せています。