npm史上最大規模となる自己増殖型ワーム「Shai-Hulud」によるサプライチェーン攻撃

はじめに

2025年9月15日、JavaScript の主要パッケージエコシステムである npm において、これまでにない深刻なサプライチェーン攻撃が発覚しました。攻撃に使われたマルウェアは「Shai-Hulud」と名付けられており、その特徴は単なるパッケージ改ざんにとどまらず、自己伝播(ワーム)機能を備えている点にあります。これにより、感染したパッケージを利用した開発環境や CI/CD 環境から認証情報を奪い取り、さらに別のパッケージを自動的に改ざんして公開するという、従来の攻撃よりもはるかに広範な拡散が可能となりました。

被害は短期間で拡大し、確認されただけでも 200件近い npm パッケージが改ざんされており、その中には広く利用される有名ライブラリや大手企業関連のパッケージも含まれていました。OSS エコシステムは世界中の開発者や企業が依存する基盤であり、サプライチェーン攻撃は一部のパッケージ利用者だけでなく、そこからさらに派生する数多くのソフトウェアやサービスへ影響を与える可能性があります。

今回の Shai-Hulud 攻撃は、サイバー攻撃者がいかに OSS エコシステムを効率的な攻撃対象と見なしているかを改めて示すものであり、npm を利用するすべての開発者・組織にとって重大な警鐘となっています。本記事では、攻撃の概要や技術的な特徴を整理するとともに、想定されるリスクと具体的な対応方法について解説します。

背景

近年、ソフトウェアサプライチェーン攻撃は頻度と巧妙性を増しています。オープンソースパッケージは多くのプロジェクトで基盤的に利用されており,単一の改ざんが間接的に多数のシステムへ波及するリスクを常に伴います。特に JavaScript/npm エコシステムでは依存関係の深さと枝分かれが大きく,一つの小さなユーティリティが数千の最終アプリケーションに取り込まれることが珍しくありません。結果として,攻撃者は影響範囲を指数的に拡大できる利点を得ます。

npm は公開・配布のプロセスを自動化するためにトークンや CI ワークフローに依存していますが,これらは適切に管理されないと大きな攻撃面となります。長期有効の publish トークン,権限が過大な CI ランナー,組織共有の認証情報は侵害時に「自動で書き換える」「自動で公開する」といった自己伝播的な悪用を可能にします。加えて,postinstall 等の実行時フックはビルドや開発環境で任意コードを実行するため,ここに悪意あるコードが紛れ込むと検出が遅れやすい設計上の脆弱性があります。

運用面でも課題があります。開発者は多数の依存を素早く取り込みたいため,package-lock による固定や署名付き配布を怠りがちです。企業では利便性のためにトークンを共有したり,CI 用イメージやランナーを長期間使い回したりする運用が残存します。これらの実務的な慣行は,攻撃者にとって短時間で大規模な被害を生む温床となります。

過去のサプライチェーン攻撃の教訓から,検出と封じ込めには「開発環境・CI・レジストリ」の三点同時対応が必要であることが分かっています。Shai-Hulud のように自己伝播性を持つ攻撃は,これら三領域のいずれか一つでも緩みがあると急速に広がります。したがって,本件は単なるパッケージ単位の問題ではなく,組織の開発・配布プロセス全体を見直す契機として位置づけるべき事象です。

攻撃の技術的特徴

初期侵入

攻撃者は npm の publish トークンや GitHub の Personal Access Token(PAT)などの認証情報を取得して改ざんに利用しました。トークン取得経路としてはフィッシングや公開設定ミス、漏洩した CI 設定などが想定されます。これらのトークンはパッケージ公開権限を直接与えるため,侵害されると改ざんが短時間で実行され得ます。

改ざん手法

改ざん版には postinstall フックやバンドル化された実行スクリプト(例:bundle.js)が組み込まれます。npm install 時に自動実行されるため,開発者や CI が気づきにくく,ビルド段階でコードが動作する設計上の盲点を突きます。

情報収集と流出

実行スクリプトはローカル環境(環境変数、.npmrc 等)とクラウド環境(IMDS 等のメタデータエンドポイント)を探索して認証情報を収集します。収集したデータは攻撃者管理下の GitHub リポジトリやハードコードされた webhook にコミット/POST される仕組みが確認されています。

自己伝播(ワーム化)

感染した環境に残る有効トークンを悪用し,攻撃者は他パッケージを自動で改ざん・公開します。依存関係を介して連鎖的に拡散する点が本件の特徴です。短命で終わらない仕組みになっているため封じ込めが難しくなります。

持続化と権限操作

攻撃スクリプトは GitHub Actions ワークフローを追加したり,リポジトリを private→public に変更するなどして持続化と露出拡大を図ります。これにより単発検出後も再侵害や情報漏えいが継続するリスクが残ります。

検出困難性と難読化

実行コードはバンドル・難読化され,ファイル名やワークフロー名を変えることで痕跡を隠します。postinstall の存在自体が通常の開発フローの一部であるため,単純な目視だけでは発見されにくい設計です。

想定される影響と懸念

1. 認証情報・機密情報の流出と二次被害

改ざんされたパッケージの postinstall や実行スクリプトが開発端末・CI・クラウドのメタデータからトークンやキーを収集し外部に送信します。流出した認証情報は即時に不正利用され、以下の二次被害を引き起こす可能性があります。

  • リポジトリの不正操作(コミット、ワークフロー変更、公開設定切替)によるさらなる改ざん。
  • クラウド資源の不正利用(インスタンス起動、ストレージ操作、データベースアクセス)。
  • サードパーティサービスの乗っ取り(npm、CIサービス、サードパーティAPI)。

2. 依存関係を介した連鎖的な感染拡大

npm の依存グラフは深く広いため、ワーム的に拡散すると多数のプロジェクトに連鎖的影響が及びます。特に共有ライブラリやユーティリティが汚染されると、最終的な配布物や商用サービスにもマルウェアが混入するリスクが高まります。結果として被害の「範囲」と「追跡可能性」が急速に拡大し、封じ込めコストが指数的に増加します。

3. ビルド・デプロイチェーンの汚染と運用停止リスク

CI/CD パイプラインやビルドアーティファクトにマルウェアが混入すると、デプロイ先環境まで影響が及びます。企業は安全確認のためにビルド/デプロイを一時停止せざるを得なくなり、サービス停止やリリース遅延、ビジネス機会の損失につながります。

4. 検出困難性と長期的残存リスク

postinstall 実行や難読化されたスクリプトは発見が遅れやすく、感染が既に広がった後で検出されるケースが多くなります。さらに、改ざんコードが複数ファイルやワークフローに分散して保存されると、完全除去が難しく「再発」や「潜伏」が残るリスクがあります。

5. 信頼性・ブランド・法務的影響

顧客やパートナーに供給するソフトウェアにマルウェアが混入した場合、信頼失墜や契約違反、損害賠償請求につながる可能性があります。規制業界(金融・医療など)では報告義務や罰則が発生する場合があり、法務・コンプライアンス対応の負荷が増します。

6. インシデント対応コストと人的負荷

影響範囲の特定、シークレットのローテーション、CI の再構築、監査ログ解析、顧客対応など、対応工数とコストは大きくなります。特に短時間で多数のチーム・プロジェクトにまたがる場合、人的リソースの逼迫と対応優先順位の決定が課題となります。

7. 長期的なサプライチェーン健全性の劣化

繰り返しの改ざん事件は OSS 利用に対する過度な懸念を生み、外部ライブラリの採用抑制や自家製化(in-house)への回帰を促す可能性があります。これにより開発効率が低下しエコシステム全体の健全性に悪影響が及ぶ恐れがあります。

8. 観測・検出のギャップによる見落とし

短時間に大量の npm publish やワークフロー変更が行われた場合でも、既存の監視ルールでは閾値を超えるまで気付かない運用が珍しくありません。ログ保持期間やログの粒度が不十分だと、フォレンジック調査の精度が低下します。

マルウェアのチェック方法


セキュリティ専門企業のAikido Securityから対策パッケージが提供されています。

特徴

  • npmやyarnなどのパッケージマネージャのコマンドをラップし、パッケージインストール前にマルウェアチェックを実施します。
  • チェックはAikido Intelというオープンソースの脅威インテリジェンスに照らし合わせて検証します。
  • デフォルトではマルウェアが検出されるとインストールをブロックしてコマンドを終了します。これはユーザーに許可を求めるモードにも設定変更可能です。
  • 対応シェルは、Bash、Zsh、Fish、PowerShell、PowerShell Core
  • Node.js 18以上に対応してます。

といった特徴を持っています。

使い方

npmコマンドを使ってAikido Security Chainパッケージをインストールします。

$ npm install -g @aikidosec/safe-chain

added 110 packages in 6s

29 packages are looking for funding
  run `npm fund` for details

次に以下のコマンドを実行してシェル統合を設定します。

$ safe-chain setup
Setting up shell aliases. This will wrap safe-chain around npm, npx, and yarn commands.

Detected 3 supported shell(s): Zsh, Bash, Fish.
- Zsh: Setup successful
- Bash: Setup successful
- Fish: Setup successful

Please restart your terminal to apply the changes.

使用できるようにするにはターミナルを再起動してください。exec $SHELL -lでも動作しました。

インストールができたかどうかは以下のコマンドで確認します。インストールしようとしているパッケージはマルウェアとしてフラグされている無害なパッケージでシェル統合が成功しコマンドが正常にラップされている場合はブロックが成功します。

$ npm install safe-chain-test
✖ Malicious changes detected:
 - safe-chain-test@0.0.1-security

Exiting without installing malicious packages.

成功すればマルウェアのチェックが有効になっています。このチェックはパッケージのインストール時に行われるため、すでにプロジェクトがある場合は、一旦node_modulesを削除してからnpm installしてください。

$ rm -rf node_modules
$ npm install
✔ No malicious packages detected.
npm warn deprecated source-map@0.8.0-beta.0: The work that was done in this beta branch won't be included in future versions

added 312 packages, and audited 313 packages in 2s

73 packages are looking for funding
  run `npm fund` for details

1 low severity vulnerability

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

これは私が開発中のライブラリで試した結果です。基本的に外部ライブラリに依存していないので、マルウェアは検出されませんでした。

一部開発用パッケージやMCP関連パッケージも標的になっていたので、グローバルインストールされているパッケージについても確認してください。グローバルパッケージの場合は対象パッケージを再度インストールすることでチェックができます。

アンインストール

アンインストールする場合は、

safe-chain teardown

でエイリアスを除去し、

npm uninstall -g @aikidosec/safe-chain

でパッケージをアンイストールし、ターミナルを再起動してください。

CI/CDへの組み込み方法

CI/CDへの組み込み方法についてもガイドされています。

マルウェアを検知するためにディスクをスキャンするため、多くのパッケージに依存している場合はCIにかかる時間の増大やコスト増大を招く場合があります。影響を考慮して導入の可否を判断してください。

GitHub Actionsでの組み込み方法について見ていきます。

私が実際に使っている.github/workflows/ci.yamlは以下のようになっています。

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18.x, 20.x]

    steps:
      - uses: actions/checkout@v4

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: "npm"

      - run: npm install -g @aikidosec/safe-chain
 
      - run: npm install
      - run: npm run lint
      - run: npm run build --if-present
      - run: npm test

npm installを行う前にパッケージをインストールします。

      - run: npm install -g @aikidosec/safe-chain

      - run: npm install

次にnpm installのコマンドをaikido-npmに差し替えます。

      - run: aikido-npm install

これらの修正を行なった.github/workflows/ci.yamlは以下のようになります。

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18.x, 20.x]

    steps:
      - uses: actions/checkout@v4

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: "npm"

      - run: npm install -g @aikidosec/safe-chain

      - run: aikido-npm install
      - run: npm run lint
      - run: npm run build --if-present
      - run: npm test

以下はGitHub Actionsの実行結果の抜粋です。マルウェアのチェックが成功していることが確認できます。

Run aikido-npm install
Scanning 312 package(s)...
No malicious packages detected.
npm warn EBADENGINE Unsupported engine {
npm warn EBADENGINE   package: '@isaacs/balanced-match@4.0.1',
npm warn EBADENGINE   required: { node: '20 || >=22' },
npm warn EBADENGINE   current: { node: 'v18.20.8', npm: '10.8.2' }
npm warn EBADENGINE }

CI/CDへの組み込みも比較的簡単に実施可能です。

まとめ

今回の Shai-Hulud 攻撃は、npm エコシステムにおけるサプライチェーンの脆弱性を突いた、これまでにない規模と性質を持つ事例でした。単なるパッケージ改ざんにとどまらず、インストール時に自動実行されるスクリプトを利用して認証情報を盗み取り、その情報を活用して別のパッケージを改ざんするという「自己伝播」の性質を持つ点が特に深刻です。これにより、短期間で数百件規模のパッケージが感染する事態となり、ソフトウェアサプライチェーン全体の信頼性に大きな影響を与えました。

本記事では、攻撃の仕組みと影響だけでなく、実際に開発者や企業が取るべき対応についても整理しました。具体的には、感染パッケージの特定と除去、シークレットの全面ローテーション、CI/CD 環境のクリーン再構築、リポジトリやログの監査といった即時対応が必須です。さらに、長期的には権限の最小化や ephemeral runner の利用、SBOM の生成とソフトウェアコンポーネント解析、そして Aikido Safe Chain のようなマルウェア検証ツールの活用など、セキュリティを日常の開発プロセスに組み込む工夫が欠かせません。

特に、CI/CD への統合は鍵となります。開発者が手動で確認するだけでは限界があるため、依存関係の取得やビルドのたびに自動でパッケージを検証し、IOC や脅威インテリジェンスに基づいてブロックする仕組みを導入することで、攻撃の拡大を未然に防げます。OSS に依存する開発体制を維持する以上、こうした仕組みは「特別な対策」ではなく「標準的な衛生管理」として定着させる必要があります。

Shai-Hulud は終息したインシデントではなく、今後の攻撃者の戦術を示す前兆と捉えるべきです。攻撃はますます自動化・巧妙化し、検出をすり抜けて広範囲に広がることが想定されます。したがって、本件を単なる一過性の脅威と見るのではなく、ソフトウェアサプライチェーン防御の基盤整備を加速させるきっかけとすることが重要です。OSS エコシステムと開発者コミュニティの健全性を守るためには、開発者一人ひとりがセキュリティ意識を高め、組織全体として持続的な監視と改善の仕組みを整備していくことが求められます。

参考文献

モバイルバージョンを終了