【Shai-Hulud 2.0】npmサプライチェーン攻撃で実際に行った影響調査と復旧手順

saratogax
記事内に商品プロモーションを含む場合があります

2025年11月、npm レジストリの正規パッケージに悪性コードが混入するという重大インシデントが発生しました。

このインシデントは 「Shai-Hulud 2.0」 と呼ばれ、感染したパッケージがインストール先の認証情報を盗み、その認証情報で別のパッケージへ自己増殖していくワーム型の攻撃でした。

特に @postman/tunnel-agent が主要な感染経路のひとつとされ、世界的に大きな影響を与えています。

これは 「正規メンテナーアカウントが侵害され、正規パッケージの最新版にマルウェアが混入する」 という非常に危険な攻撃手法です。

本記事では、

  • 今回の攻撃手法のポイント
  • 私のプロジェクトで影響が想定されたパッケージ
  • 実際に行った安全対策
  • CI/CD(GitHub Actions)の改善ポイント
  • 再発防止のための運用方針

を整理して紹介します。

同じように npm パッケージを利用している開発者の参考になれば幸いです。

📌 今回の npm 攻撃の概要

今回のインシデントは、一般的なnpm installの仕組みを悪用した巧妙な攻撃でした。

▶ 攻撃の流れ(概要)

  1. 正規パッケージのメンテナーアカウントが侵害される
  2. 正規パッケージの「新バージョン」に悪意ある preinstall スクリプトが混入
  3. npm install 時に preinstall が自動実行
  4. マルウェアが各種認証情報を窃取し、攻撃者のリポジトリに送信

盗まれる可能性があった情報には、以下が含まれます。

  • GitHub Personal Access Token (PAT)
  • npm token
  • クラウドサービス(AWS, GCP, Azureなど)の認証情報
  • CI/CD のシークレット
  • 環境変数全般

つまり 「たった一度の npm install」が致命的な被害につながる という危険性がありました。

📌 私のプロジェクトで問題となった依存関係

私のリポジトリでは API テスト用途で newman を利用しています。

この newman が依存している postman-request の内部で、以下のパッケージが使われています。

@postman/tunnel-agent

そして、このパッケージのバージョン履歴を見ると、問題の 2025/11/24 に以下のような「怪しい最新版」が公開されていました。
(0.6.5 以上)

$ npm view @postman/tunnel-agent time

{
  created: '2019-05-08T09:00:14.942Z',
  modified: '2025-11-25T08:04:45.566Z',
  '0.6.2': '2019-05-08T09:00:15.240Z',
  '0.6.3': '2019-11-07T05:52:12.422Z',
  '0.6.4': '2024-07-18T05:52:19.650Z',
  '0.6.5': '2025-11-24T05:04:37.688Z',
  '0.6.6': '2025-11-24T05:10:19.400Z',
  '0.6.7': '2025-11-24T05:13:17.472Z'
}

幸い、私の package-lock.json には 安全な 0.6.4 がロックされていましたが、もし何か変更して npm install を実行していたら 0.6.5 以上の悪性バージョンがインストールされてしまう恐れがありました。

📌 実施した対応内容

1. GitHub Actions を npm install → npm ci に変更

npm ci の特徴:

  • package-lock.json完全に忠実に再現
  • lock ファイルと矛盾があればエラー
  • 不要なバージョンへの自動更新が絶対に発生しない

CI/CD では確実に 0.6.4 のままになるため、攻撃リスクが大幅に下がります。

- name: Install packages
  run: npm ci

2. package.json に overrides を追加して強制固定

npm v8+ の overrides を使い、プロジェクト全体で @postman/tunnel-agent を 0.6.4 に強制固定 しました。

"overrides": {
  "@postman/tunnel-agent": "0.6.4"
}

これにより、

  • 間接依存(transitive dependency)でも 0.6.4 に固定
  • 誤って npm install を実行しても 0.6.5+ に上がらない

という二重の安全性を確保できます。

3. 過去の GitHub Actions を確認し、危険な更新がなかったことを確認

actions/cache を使っていたため、

  • 11/24 や 11/25 にキャッシュが作り直されていないこと
  • 最新キャッシュが問題発生前のものだったこと

をログから確認し、過去に悪性バージョンを踏んでいないことを確認しました。

4. ローカルで npm install を行わない運用に変更

ローカル環境は必要最低限であったり一時的(短時間)ではあるものの、GitHub PAT やクラウドクレデンシャルなどを保持しているため、万が一でも悪性パッケージを踏むと影響が大きいです。

そのため、

  • ローカルは基本 npm ci
  • 依存更新が必要なときのみ、隔離環境で npm install
  • 普段の開発では npm install を使わない

こうした運用方針で今回の対応は行いました。

📌 まとめ:今回の npm インシデントから学んだこと

今回のサプライチェーン攻撃を通して、個人的に強く感じたポイントは次の3つです。

  • 依存の更新は“リスク”でもある
    最新版を取るだけで汚染物が入る可能性がある。ロックファイルの運用や依存管理は本当に重要。
  • npm install を軽く使わない
    ローカルで安易に install すると、CI より先に“汚染バージョンが混入”するリスクがある。
  • CI とローカル開発の再点検が必要
    npm ci の利用、overrides の活用など、日常的な運用を見直すきっかけになった。

🔐 最後に:同じ状況に遭遇した場合の行動指針

もし今回と同じようなサプライチェーン攻撃に遭遇した場合、私なら次の2つを最優先で行います。

1. 影響バージョンをインストールしていないか確認する

CI/ローカル両方の環境で、汚染パッケージが混入していないかを確認する。

2. “入れてしまった可能性” があるなら、秘密情報を必ずローテーションする

仮に実行されていなかったとしても、汚染パッケージにトークンや鍵を送信するコードが仕込まれていた可能性 があるためです。

ローテーションすべき情報は以下の通り。

  • GitHub の Personal Access Token (PAT)
  • CI/CD の環境変数(API キー、アクセストークン)
  • クラウドプロバイダのアクセスキー(AWS IAM 等)
  • 特殊な CLI の auth トークン(Firebase、Vercel、Netlify など)

特に CI 環境に汚染バージョンが入り込むと、ビルド時の環境変数が一括で盗まれる可能性がある ため、早めのローテーションがもっとも現実的な防御になります。

npm だけではなく、サプライチェーン攻撃は誰でも遭遇しうるもの。

今回の経験が、同じ状況に直面した方の役に立てば幸いです。

参考(出典)

npm のセキュリティでは、npm audit の警告が出たときの対処もあわせて確認しておくと安全です。

あわせて読みたい
npm install時にnpm auditのセキュリティ警告が出る場合の対処法
npm install時にnpm auditのセキュリティ警告が出る場合の対処法

npm publish でパッケージに含めるファイルを必要最低限に絞る方法は、以下の記事で解説しています。

あわせて読みたい
npm publishするパッケージを必要最低限のファイルのみにする
npm publishするパッケージを必要最低限のファイルのみにする
ABOUT ME
saratoga
saratoga
フリーランスエンジニア
仕事にも趣味にも IT を駆使するフリーランスエンジニア。技術的な TIPS や日々の生活の中で深堀りしてみたくなったことを備忘録として残していきます。
記事URLをコピーしました