cat posts/%e4%bb%8a%e9%80%b1%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%e8%80%83%e5%af%9f%ef%bc%9a%e8%8d%b7%e7%89%a9%e3%81%ae%e4%b8%ad%e3%81%ab%e9%85%8d%e9%81%94%e5%93%a1%e3%81%8c%e6%bd%9c.md

今週のセキュリティ考察:感染先から次へ乗り移る——npm ChainDrop サプライチェーンワーム

npm で配布されているキャッシュ用ライブラリ keyv の 6.0.0 に、認証情報を盗むワーム(自分で増殖する不正プログラム)が仕込まれ、2026年8月4日に数百のパッケージへ広がった。BleepingComputer はこれを ChainDrop と呼んでいる[1][3][4]。

PART 1解説

3行でわかる要点

  • 規模:SafeDep が確認した汚染は 79 パッケージ・353 バージョン。関連パッケージの月間ダウンロード数の合計は 20 億と報じられた[1][3][4]。
  • 仕組み:インストール時に自動で動く preinstall スクリプトで盗み出しプログラムを実行し、盗んだ npm の公開権限を使って別のパッケージも汚染する[2][3]。
  • もう一つの経路:リポジトリには Claude Code と VS Code の設定(起動時のフックや自動タスク)も仕込まれ、ワークスペースを信頼すると実行されうる[3]。

前提:npm とインストール時のスクリプト

npm は JavaScript(Node.js)のライブラリを配布する仕組みで、npm install で必要なライブラリと、それが依存するライブラリをまとめて取り込みます。npm には、インストールの前後に任意の処理を自動で実行する機能(ライフサイクルスクリプト)があり、部品のビルドなど正規の用途でも使われています[5]。

便利な一方で、悪性のパッケージを入れただけで、開発者の PC や CI の中でプログラムが動いてしまいます。開発環境には、ソースコードを公開するための権限やクラウドの鍵がそろっているため、攻撃者にとって価値の高い場所です。

まず押さえる用語

用語ひとことでもっと詳しく
ワーム感染した先から、自分を別の場所にコピーして広がる不正プログラム。—
サプライチェーン攻撃ソフトウェアの部品や配布の経路を汚染し、それを使う多くの利用者に被害を広げる攻撃。IPA「情報セキュリティ10大脅威」
preinstall スクリプトnpm install のときに自動で実行される処理。正規の用途も多いが、悪用されると入れただけで動く。npm Docs「scripts」
来歴証明(provenance)「どのリポジトリのどのビルド手順で作られたか」を証明する仕組み。中身が安全かまでは保証しない。—

本来の仕組みと、どこが破られたか

npm パッケージの公開と利用の正常時と攻撃時正常時保守者が開発正規の手順で公開利用者がinstallライブラリを使う攻撃時悪性コードを混入正規の手順で公開install で盗み出し別の包みも汚染
図1 盗んだ公開権限で、別のパッケージにも自分を仕込んで広がる(SafeDep・Socket・The Hacker News の記述をもとにした概念図)

悪性の keyv 6.0.0 は、プロジェクトの正規の GitHub Actions を通って公開されたため、来歴証明も正しいものでした[3]。図1の2段目の「正規の手順で公開」が、攻撃時にも同じなのはこのためです。

違いは、インストールした環境で preinstall スクリプトが盗み出しプログラムを動かし、その環境にある npm の公開権限を使って、さらに別のパッケージを汚染していく点です[2][3]。npm 12 は未承認のライフサイクルスクリプトを既定で止めますが、それより前の npm などはスクリプトが動きます[3]。

攻撃の流れ

flowchart LR
    A[攻撃者] -->|悪性コードを混入| B[keyv 6.0.0]
    B -->|npm install| C[開発者やCIの環境]
    C -->|preinstallで実行| D[認証情報を盗む]
    D -->|盗んだ公開権限| E[別のパッケージを汚染]
    E -->|npm install| C
    style A fill:#c0392b,color:#fff
    style B fill:#c0392b,color:#fff
    style D fill:#e67e22,color:#fff
    style E fill:#c0392b,color:#fff
  • 盗まれる対象は GitHub、npm、クラウド、Vault、Kubernetes、データベースの認証情報や秘密鍵。GitHub Actions のランナーのメモリも読む[3]。
  • 盗み出しプログラムは、トークンが失効させられたことを検知して動く監視役も仕込む。SafeDep は、トークンを失効させる前にこの監視役を取り除くよう勧めている[1][3]。

「人気がある=安全」ではない(考察)

  • 月間のダウンロード数は「多くの人が使っている」という事実にすぎない。人気のライブラリを踏み台にすると、ゼロから悪性パッケージを公開するより多くの環境に届く。
  • 正規の CI を通ったので来歴証明は正しかった。来歴証明は「どこで作られたか」を示すが、「中身が安全か」までは保証しない[3]。
  • package-lock.json で固定していても、更新するたびに差分を見なければ、依存の依存として汚染された版が入る。

いま確認すること

  • 【npm を使っている】該当パッケージの汚染された版を入れた端末や CI は、認証情報が漏れた前提で扱い、監視役を取り除いてからトークンを変更する[1][2][3]。
  • 【npm を使っている】npm 12 の未承認スクリプトの既定ブロックを使う。古い npm ではスクリプトの実行を制限する設定を検討する[3]。
  • 【全員】インストール時に任意のコードが走る仕組みは npm に限らない(Python の setuptools、Rust の build.rs など)。今週更新された依存関係の差分を確かめたか。
# 既知の脆弱性と依存関係を確認する
npm audit
# lock file の意図しない変更がないか確認する
git diff package-lock.json | grep '"version"'

出典・参考リンク

報道・解説

  1. SafeDep — keyv npm supply chain compromise
  2. Socket — Popular npm packages in the Keyv and Cacheable namespaces compromised
  3. The Hacker News — Keyv-Linked npm Worm Poisons Hundreds of Packages
  4. BleepingComputer — Massive ChainDrop npm supply chain attack

用語解説

  1. npm Docs — npm approve-scripts

PART 2問題(情報処理安全確保支援士 試験形式)

問1 午前II形式(4択)

npm で確認された keyv を発端とするワーム(ChainDrop)が、通常のサプライチェーン攻撃と異なる点として、最も適切なものはどれか。

  • ア 盗んだ npm の公開権限を使い、別のパッケージにも自分を仕込んで広がる
  • イ 開発者の PC ではなく、npm レジストリのサーバー自体を暗号化する
  • ウ ダウンロード数の少ないパッケージだけを狙って公開される
  • エ 開発環境では動作せず、本番環境でのみ動作する
解答・解説を表示

解答:ア

通常のサプライチェーン攻撃は汚染したパッケージを配って終わるが、今回は盗んだ公開権限で別のパッケージを汚染していく自己増殖型だった。イは報告にない。ウは逆で、多くのプロジェクトが使う keyv を踏み台にした。エも逆で、インストールした開発環境や CI で動く。

↑ Part 1「本来の仕組みと、どこが破られたか」を読み直す

問2 午後形式(記述)

A社は package-lock.json を git で管理しており、「依存パッケージのバージョンは固定している」と考えていた。しかし keyv を発端とするワームの報道を受けて調べたところ、①直接は依存していない keyv が、依存の依存としてプロジェクトに含まれていた。

設問 本文中の下線①を踏まえて、A社が依存関係を更新するときに確認すべきことを50字以内で述べよ。

解答・解説を表示

解答例:lock file の差分で、間接依存を含めどのパッケージのどのバージョンが変わったか(43字)

lock file は固定はしてくれるが、更新のたびに差分を見なければ、汚染されたバージョンもそのまま入る。git diff package-lock.json で変わったバージョンを確かめ、npm audit も通す。「最新版にそろえる」は、汚染版を取り込む動きそのもの。

↑ Part 1「「人気がある=安全」ではない」を読み直す