【緊急対策あり】npm史上最悪のワーム攻撃『Shai-Hulud』とTinyColor侵害の全貌

はじめに

2025年9月中旬ーJavaScriptエコシステムを揺るがす深刻な事件が発覚しました。
その名も 「Shai-Hulud」 ──npm史上最悪と呼ばれるワーム型攻撃です。

この攻撃は、広く利用されている TinyColor を含む500以上のパッケージを侵害し、開発環境やCI/CDパイプラインを通じて拡散しました。
従来の「マルウェア仕込みパッケージ」事件とは一線を画し、自己複製・自己拡散を行うワーム型 という点で極めて危険性が高いものでした。

サプライチェーン攻撃はもはや珍しい話ではなくなりましたが、今回の件は「npmエコシステム全体の信頼性」を揺さぶるほどの規模。

開発者が日常的に行っている npm install という行為そのものが、攻撃の入り口になってしまったのです。

本記事では以下を整理して解説します。

  • Shai-Hulud攻撃の概要と手口
  • TinyColorを含む侵害パッケージの実態
  • 技術的リスクと被害シナリオ
  • 今すぐできる防御策とチェックリスト

「npmの依存関係は、便利であると同時に最大の弱点でもある」──その現実を直視しながら、開発者一人ひとりが取るべき行動を考えていきます。

攻撃概要と技術的リスク

Shai-Huludとは?

Shai-Hulud(シャイ・フルード) は、2025年に確認された npm 史上最大級のサプライチェーン攻撃です。従来の「改ざんされた1つのパッケージ」が問題になるケースと違い、この攻撃は ワーム型(自己拡散型) で、侵害したアカウントを利用して次々と他のパッケージへ感染を広げました。

被害範囲は非常に広く、TinyColor(@ctrl/tinycolor) を含む有名ライブラリから、中小規模の依存パッケージまで影響が及びました。初期報告では40件以上、のちに数百件規模に拡大したとされています。

TinyColorとは?

TinyColor は、JavaScriptで色(RGB, HEX, HSL など)を簡単に扱うための軽量ライブラリです。
Webデザインやフロントエンド開発において「色を明るくする」「透明度を調整する」「補色を求める」といった処理を直感的に書けるため、BootstrapやChart.jsなど多くのプロジェクトで利用されてきました。

そのシンプルさから 「色操作の定番ツール」 として知られ、直接依存していない開発者でも間接的に依存関係に含まれることが多いパッケージです。
今回の事件では、その「どの現場にも入り込んでいる」特性が被害拡大の大きな要因となりました。


攻撃の手口

  1. アカウント侵入 攻撃者はまず npm や GitHub の開発者アカウントを突破。パスワード漏洩やアクセストークン窃取が起点と考えられています。

  2. 悪意ある postinstall スクリプト 侵害されたパッケージには postinstall に不正スクリプト(bundle.js)が仕込まれました。利用者が npm install を実行すると自動的に動作し、環境内の情報を収集して外部へ送信します。

  3. 情報収集と漏洩

    • process.env から GitHub / npm / AWS / GCP などの認証情報を探索
    • .npmrc ファイルやクラウドキーを抽出
    • 高エントロピー文字列をスキャンし、秘密情報を「Shai-Hulud」というリポジトリにアップロードするケースも確認されました。
  4. 自己拡散 盗んだ npm トークンを使い、同じ開発者が管理する別のパッケージにも不正コードを注入して公開。さらに GitHub Actions などの CI/CD 環境に悪意あるワークフローを仕込むことで、感染範囲を一気に拡大しました。


リスクと被害シナリオ

  • クラウド乗っ取り 環境変数や設定ファイルから取得した API キーを使い、AWS・GCP・Azure 等の資源が不正利用される可能性。

  • CI/CD 汚染 ビルドサーバやデプロイ環境に侵入すれば、プロダクトにマルウェアを混入させてしまうリスク。

  • サプライチェーン全体の信用低下 パッケージ利用者が気付かないまま悪意あるバージョンを取り込み、さらにそのプロダクトのユーザーにまで影響が及ぶ。


具体的な被害例(確認済み)

パッケージ 被害バージョン
@ctrl/tinycolor 4.1.1, 4.1.2
ngx-bootstrap 18.1.4, 19.0.3, 20.0.4〜20.0.6

これらは npm 側から既に削除・修正済みですが、過去にインストール済みの環境では依然として痕跡が残っている可能性があります。


既知の被害パッケージ例・被害バージョン

パッケージ 被害バージョン
@ctrl/tinycolor 4.1.1, 4.1.2 ([Ox Security][2])
ngx-bootstrap 18.1.4, 19.0.3, 20.0.4~20.0.6 等 ([Snyk][6])

背景:npm依存構造の弱さ

JavaScriptエコシステム、特に npm は「小さなモジュールを組み合わせて大きなアプリを作る」文化が根付いています。数十行しかない便利関数が独立したパッケージとして公開され、それを何百・何千と組み合わせてプロジェクトを構築する──この柔軟性こそが npm の強みであり、同時に最大の弱点でもあります。

  • 依存の入れ子構造 自分が直接インストールしたライブラリのさらに奥に、また別の依存がある「依存の連鎖」。結果として、自分が知らないパッケージまでプロジェクトに組み込まれてしまいます。

  • トランジティブ依存の盲点 TinyColor のような「基盤的な小規模ライブラリ」が侵害されると、無数のプロジェクトに波及します。実際、多くの開発者は「TinyColorを直接使っていなかったのに被害範囲に入っていた」という状況に直面しました。

  • postinstallスクリプトの危険性 npm は postinstall に任意の処理を許しており、ユーザーが気付かぬまま外部通信やファイル改変が実行されます。利便性と引き換えに、攻撃者にとって格好の侵入口となっています。

つまり npm の構造は、「1つの脆弱な部品が連鎖的に全体を崩すドミノ倒し」 になりやすいのです。Shai-Hulud事件はその典型例でした。


開発者が取るべき対策

Shai-Huludのような攻撃を完全に防ぐことは難しいですが、リスクを最小化する習慣を取り入れることで被害確率を大きく下げられます。以下に実践的な対策をまとめます。

1. 依存関係の可視化と監査

  • npm listyarn list で依存ツリーを確認。
  • npm audityarn audit で既知の脆弱性を定期チェック。
  • 不要な依存は削除し、依存の数自体を減らす。

2. lockfile を厳格に管理

  • package-lock.jsonyarn.lock を必ずバージョン管理に含める。
  • CI/CD 環境では npm ci を利用し、予期せぬバージョン更新を防止。

3. postinstall スクリプトの警戒

  • grep -R "postinstall" package-lock.json で怪しい処理がないか調査。
  • 公式でないパッケージの postinstall 実行には注意。

4. 実行環境の隔離

  • 信頼できないパッケージは Docker / VM 内で試す。
  • CI/CD サーバでは最小権限ユーザーでビルドを行い、環境変数をむやみに渡さない。

5. 認証情報の保護

  • .npmrc にアクセストークンを直書きしない。
  • GitHub / npm / クラウドトークンは短期有効+定期ローテーション。
  • dotenv やシークレットマネージャを活用して管理。

6. OSレベルの防御

  • AppArmor や SELinux を有効化し、npm 実行プロセスをサンドボックス化。
  • ufw/iptables で不審な外部通信を検知・遮断。

7. 最後の砦:バックアップ

  • 定期的にプロジェクトやサーバのバックアップを取り、侵害時に「やり直せる状態」を確保する。

実践チェックリスト

Shai-Hulud事件のような大規模攻撃に備えて、開発者が日常的に実践できるチェック項目を整理しました。

  • npm audit を定期的に実行して脆弱性を洗い出す
  • package-lock.json / yarn.lock をリポジトリに必ずコミット
  • npm ci を使い、CI/CD 環境での依存バージョンを固定
  • 依存ツリーを確認し、不審な postinstall がないか grep で調査
  • 知らないパッケージを安易に追加しない(特に小規模・新規公開のもの)
  • 開発用と本番用の認証情報を分離し、トークンは短期ローテーション
  • npm install は隔離環境(Docker/VM)で検証してから利用
  • サーバやPCに AppArmor / SELinux を有効化
  • 定期バックアップを取り、「最悪は巻き戻せる」状態を確保

このリストを定期的にチェックするだけで、リスクは大幅に下がります。


まとめ

Shai-Huludは「npmの歴史上、最悪のサプライチェーン攻撃」と呼ばれるにふさわしい規模と影響力を持っていました。TinyColor のような誰もが安心して使っていたライブラリですら侵害される──これは、私たちが「依存を信頼する」ことの危うさを示しています。

便利さとスピードを追い求めるほど、セキュリティは後回しになりがちです。しかし、npm install という日常的な操作が攻撃の入り口になる時代だからこそ、開発者一人ひとりの小さな習慣が大きな防御壁になるのです。

  • 依存を盲目的に信じない
  • バージョン管理と監査を徹底する
  • 実行環境を隔離して守る

この3つを実践するだけでも、Shai-Huludのような攻撃の被害を最小限に抑えられます。

「npmは危ないから使うな」ではなく、正しい理解と習慣で安全に使い続ける──それが、今回の事件から得るべき最大の教訓でしょう。

具体的対策サンプル(コード/コマンド案)

1. 依存に TinyColor が含まれているか確認

# プロジェクト全体の依存をリスト化して TinyColor を検索
npm list @ctrl/tinycolor
npm ls tinycolor

もし @ctrl/tinycolor@4.1.14.1.2 が含まれていたら、侵害されたバージョンなので即更新または削除を検討してください。


2. postinstall スクリプトの有無を調査

# package-lock.json と node_modules 以下から postinstall を検索
grep -R "postinstall" package-lock.json node_modules

不明なライブラリに postinstall が含まれている場合は、内容を必ず確認しましょう。攻撃コードはこのフックに仕込まれていました。


3. Docker で安全に npm install を検証

# Node.js 公式イメージを利用し、隔離環境で npm install を実行
docker run -it --rm -v "$PWD":/app -w /app node:20 bash
npm install

この方法ならホスト環境の認証情報やファイルを守りつつ、依存が安全に解決されるかテストできます。


4. npm audit / audit fix の利用と限界

# 既知の脆弱性をチェック
npm audit

# 自動で修正できるものを更新
npm audit fix

ただし注意点として、npm audit は既知の脆弱性のみを検出するため、ゼロデイ攻撃や今回の Shai-Hulud のような「新規侵害」は検出できません。 そのため audit は万能ではなく、**「最低限の健康診断」**と割り切ることが重要です。