はじめに
こんにちは!
株式会社C&Pの武智です。
最近、npm install
を実行しましたか?
この記事が、ローカル環境や管理するnpmパッケージに、いとも簡単に悪意あるコードが入る危険性を知るきっかけ、そしてフィッシングの危険性を今一度認識するきっかけになればと思います。
私は最近まで「このパッケージは大丈夫だろう」と、npmからインストールされるもの、そしてそのパッケージが依存するまた別のパッケージまで深く意識したことがありませんでした。
※この記事は一部AIを使用しております。
何があったか
「自分のnpmパッケージが勝手に他のパッケージを攻撃する」
SFの世界の話みたいですが、これが2025年9月に実際に起きました。攻撃者が一度仕掛けるだけで、あとは悪意のあるコードが自動的に感染を広げていく...まさに悪夢のようなシナリオです。
まず9月上旬に、debugやchalkといった超メジャーなパッケージ(合計26億回/週ダウンロード!)が暗号通貨盗取を目的とした攻撃を受けました。
数時間で悪意のあるバージョンが削除され、実際の暗号通貨被害はわずか5セント程度と報告されており、不幸中の幸いという形で騒動の幕は閉じました。
しかしその後、今度は毎週200万回ダウンロードされる @ctrl/tinycolor
をはじめとした180以上のパッケージに、さらに進化した悪意のあるコードが注入されちゃったんです。
そして今回の攻撃には、前回とは全く違う危険な特徴がありました...それは自己増殖型ワームというものです。
従来のコンピューターウイルスと同じ自己複製の仕組みが、今度はnpmの世界で実現されちゃったんです。
そもそもサプライチェーン攻撃って何?(レストランで例えてみた)
まず「サプライチェーン攻撃」って聞いて「???」ってなった方、安心してください。
レストランで例えてみますね。
通常の流れ:
お客さん → レストラン → 調味料メーカー → 調味料の原材料サプライヤー
攻撃された場合:
お客さん → レストラン → 調味料メーカー → サプライヤーで事件 → 毒入り原材料 → 毒入り調味料 → 全ての料理が毒される!!
サプライチェーン攻撃も同じで、開発者(レストラン)が信頼している人気パッケージ(調味料)が、実はその依存パッケージ(原材料)レベルで攻撃されていて、最終的にユーザー(お客さん)まで被害が及んじゃうんです。
しかも一つの原材料サプライヤーが影響されると、それを使う全ての調味料メーカー、そしてそれらの調味料を仕入れた全てのレストランに影響が広がります。
「うわ、考えただけで怖い...」
なんでこんなに効果的なの?
- 信頼の悪用: 開発者は「まさかこの有名なnpmパッケージが危険なわけないよね」って思ってインストールしちゃいます
- 拡散力が高い: 一個のパッケージが何千、何万ものプロジェクトで使われることで、被害が急速に広がります
- バレにくい: 正規のパッケージに偽装してるから、気づくのが遅れがちです
npmの仕組みと「落とし穴」
npmって便利すぎて、普段あんまり仕組みを意識しないですよね。
npm install パッケージ名
をポチっとするだけで、世界中の開発者が作った便利なツールを使えちゃう。
一見単純なパッケージのインストール作業ですが、実際には信頼できないパッケージを実行環境に取り込むリスクを伴います。
依存関係の連鎖が怖い
現代のWeb開発って、一つのプロジェクトで無数のパッケージを使うのが普通なんです。しかもそれらのパッケージは互いに依存し合ってる...
あなたのプロジェクト
↓ 依存
パッケージA
↓ 依存
パッケージB
↓ 依存
パッケージC(← ここが攻撃されたら?)
チェーンのどこか一箇所でも攻撃されると、最終的にあなたのプロジェクトまで影響が及んじゃうんですよね...
npmの弱点
多くのユーザーがいるnpm開発者のアカウントが侵害されると、五月雨式に影響が広がってしまいます。この構造により、自身の開発したパッケージが多くの人に使われるほど、当初は考えてもいなかった重い責任を背負うことになります。
今回紹介する1例:
- フィッシング攻撃: 開発者が偽のログインページでパスワードと2FAコードを盗まれると、アカウントが攻撃者に侵害されます
- 権限の悪用: 侵害された開発者権限を使って、正規パッケージに悪意のあるコードが注入されます
「開発者がちゃんとセキュリティ対策してれば大丈夫じゃない?」
今回の一連の攻撃では、複数のセキュリティ意識の高い開発者たちが巧妙なフィッシング攻撃にやられちゃいました。
どんなに意識が高い人でも、ヒューマンエラーは起きてしまうのです...
自己増殖型ワームとは(この仕組みが恐ろしい...)
自己増殖型ワームとは、自分自身を他のシステムに自動的に複製・拡散する悪意のあるプログラムです。今回のnpm攻撃では、一度パッケージに感染すると、そのコード自体が他のパッケージを探して自動的に感染を広げていく仕組みが実装されていました。
今回のワームの特徴:
- パッケージ管理システムを悪用した拡散: npm APIを直接操作して他のパッケージに感染
- 開発者の信頼関係を利用: 開発者から他の開発者への連鎖感染
- 新しい攻撃面: サプライチェーンという信頼されたインフラを攻撃ベクターとして活用
一度感染したら、もう攻撃者が何もしなくても勝手に感染が広がっていくんです。めちゃくちゃ怖くないですか?
これにより攻撃者は少ない労力で大規模な被害を引き起こせるようになっちゃいました。
💥 連鎖反応の恐ろしさ
- 感染パッケージがインストールされる ↓
- ワームが実行される(
postinstall
) ↓ - npmの認証情報があれば → その開発者の全パッケージを感染 ↓
- 感染したパッケージがnpmに公開される ↓
- 他の開発者がそれをインストール → サイクルが繰り返される
「npmのパッケージ作らないし、関係ないか」
ちょっと待ってください!パッケージを公開しない一般の開発者でも危険です。
一般ユーザー(npm publish権限を持たない人) がShai-Huludワームに感染したパッケージをインストールすると:
- 開発マシンの環境変数(
AWS_ACCESS_KEY_ID、GITHUB_TOKEN
など)や、GitHubの認証情報が盗まれる - 盗まれた情報が攻撃者の「Shai-Hulud」リポジトリに公開される
- TruffleHog(本来は正当なセキュリティツール)を悪用したファイルシステムの全スキャンが実行される
つまり、パッケージを公開しなくても、あなたの開発環境の機密情報は全て盗まれてしまう可能性があるんです。
「Shai-Hulud」攻撃の詳細
- 被害パッケージ数: 180以上(発覚当初の40から継続的に拡大中)
- 週間ダウンロード数: 200万回以上(@ctrl/tinycolorのみ)
- 悪意のあるバージョン: 4.1.1, 4.1.2
- 感染源: rxnt-authentication パッケージ(9月15日に最初の悪意のあるコードが注入)
「200万回って...かなりまずくない?」
そうなんです。しかもこれ、たった1つのパッケージの話です!
具体的な被害
- GitHub、AWS、GCP、Azure等開発者のクラウドサービス認証情報や、環境変数に保存されたすべての秘密情報(process.env)が盗まれる
- 例:
AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、GITHUB_TOKEN、NPM_TOKEN
など
- 例:
- GitHubリポジトリに悪意のあるワークフロー(.yml)が自動生成される
- 盗んだ情報が「Shai-Hulud」って名前の公開リポジトリに勝手に作成される
「公開リポジトリって...誰でも見れちゃうのでは」
その通りです。攻撃者だけじゃなく、世界中の誰でも盗まれた情報にアクセスできちゃう状況になってました。
暗号通貨盗取攻撃の詳細
こちらの更に規模が大きい攻撃では、Josh Junon氏をはじめとする著名な開発者のアカウントが侵害されました。
攻撃の特徴
- 主な標的: 暗号通貨の盗取
- 被害パッケージ: debug, chalk など18の人気パッケージ
- 合計ダウンロード数: 約26億回
- 送金先のすり替え: UI上で明らかな改変を避け、実際の取引を裏で捕捉・改変することで、攻撃者のアドレスに暗号通貨の送金先がこっそり変更される
攻撃の流れ(時系列順)
1. フィッシング攻撃
複数のパッケージ開発者が偽のnpmログインページにアクセスし、認証情報とワンタイムパスワードが盗まれる
2. アカウント完全掌握
攻撃者が開発者のnpmアカウントを完全にコントロール → 2FA設定まで変更して本人を締め出し
「うわ、開発者が何もできない状況だな...」
そうなんです。攻撃を受けた開発者たちは、数時間から十数時間にわたって自分のパッケージにアクセスできなくなっちゃいました。
3. 悪意のあるコード注入
難読化されたJavaScriptコードがパッケージに埋め込まれる
攻撃手法の相違点
限定的な被害範囲:
- この攻撃が暗号通貨盗取だけに狙いを絞っていたおかげで、もっと大きな被害を免れたのかもしれません。もしこれが「Shai-Hulud」攻撃のようだったらとんでもないことになってましたね。。。
二つの攻撃の比較:進化する脅威
共通点
- アカウント侵害から開始: どちらも開発者のnpmアカウントが侵害されることで攻撃が始まった
- 高い影響力: 人気パッケージを標的にして最大限の影響を狙った
進化したポイント
前回の攻撃(暗号通貨盗取):
- より直接的なアプローチ: 暗号通貨盗取のみに特化した「crypto-stealer」
- 単層の攻撃手法: ブラウザ内のAPIフッキング(fetch、XMLHttpRequest、wallet APIs)に限定
- 被害範囲: 18パッケージ(一人のパッケージ開発者が管理するパッケージ群)
今回の攻撃:
- 自己増殖機能で被害拡大:被害パッケージ数は発覚時の40から、自己増殖機能によって180以上に拡大している
- 包括的な情報収集:あらゆる種類の認証情報を標的
- 永続化機能:GitHubワークフローを使った長期的な侵害
- より危険性の高く、影響範囲が広い被害:企業の機密情報への潜在的なアクセス(TruffleHogという正規のセキュリティツールを悪用した高度な秘密情報スキャン機能を使用している)
-
ステルス性の向上:複数の技術的回避手法を組み合わせた、高度なステルス機能
-
サイレントエラーハンドリング:
catch {}
ブロックで全てのエラーを隠蔽し、ログ出力を一切残さない - 正規ツールの偽装: TruffleHogの実行を正当なセキュリティスキャンとして偽装
- 二重Base64エンコーディング: データ流出時に二重エンコーディングを行い、基本的なフィルタリングを回避
-
サイレントエラーハンドリング:
ただし、これはただ恐怖を煽りたいわけじゃないです!
事実として攻撃が進化してるから、「私たちも認識をアップデートしないといけない!」ということです。
「やばい、感染してるかも」って思った時にやること 🚨
まず、プロジェクトに感染したパッケージが含まれているかを確認しましょう。
package.jsonとpackage-lock.jsonの確認
プロジェクトルートで、直接依存および間接依存の両方から感染パッケージがないかを確認してください。npm lsコマンドやパッケージ名での検索を活用できます。
ダウンロード数が高い感染されたパッケージ:
- @ctrl/tinycolor: 4.1.1, 4.1.2
- angulartics2: 14.1.1, 14.1.2
- ngx-bootstrap: 18.1.4, 19.0.3, 19.0.4, 20.0.3-20.0.5
詳細なリスト: 180以上の被害パッケージの詳細はAikidoの分析レポートを参照してください。
Shai-Hulud リポジトリの確認
攻撃者は盗んだ情報を「Shai-Hulud」って名前の公開リポジトリに投稿しちゃいます。
GitHubの自分のリポジトリ一覧で、この変な名前のリポジトリが勝手に作成されてないかチェックしてください。もし見つけちゃったら...
ワークフローファイルの確認
プロジェクトに「shai-hulud-workflow.yml」やその他「Shai-Hulud」関連のファイルが勝手に作られてないかも見てみましょう。
環境変数のチェック
攻撃コードは特にこれらの環境変数を狙ってます:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
GITHUB_TOKEN
NPM_TOKEN
GOOGLE_APPLICATION_CREDENTIALS
これらが設定されている環境で感染パッケージが実行された場合、情報を盗まれた可能性があります。該当する認証情報がある場合は、すべて再発行することをお勧めします。
とりあえずやること
1. 感染パッケージの除去
感染したパッケージを削除するか、安全なバージョンにダウングレードしてください。package.jsonとpackage-lock.jsonの両方を更新し、依存関係を再構築することが重要です。
2. 認証情報の全面リセット
「めんどくさいな〜」って思うかもしれませんが、これ超重要です!
3. リポジトリの大掃除
悪意のあるワークフローファイル(.github/workflows/shai-hulud-workflow.yml)を削除して、package.jsonの変更履歴を確認し、不審な修正がないかチェックしてください。
長期的なセキュリティ強化
依存関係の管理改善
1. バージョンを固定してみる
範囲指定(^や~)じゃなく、具体的なバージョン番号を指定してpackage.jsonに記載してみる
2. 定期的な健康診断
npm auditコマンドで使用中のパッケージに脆弱性がないかをチェックする
開発環境のセキュリティ
1. 最小権限の原則:
- 開発環境では必要最小限の権限のみ
- 本番の認証情報は開発環境に置かない
2. 環境の分離:
- 開発、ステージング、本番をきっちり分ける
- それぞれ独立した認証情報を使用
3. 段階的デプロイ:
- 新しい依存関係には「待機期間」を設ける
- 自動デプロイ前に人間の目でチェック
「待機期間って何?」
新しくリリースされたパッケージを一定期間待ってからインストールするルールのことです。多くのサプライチェーン攻撃は最初の24時間以内に検出されるため、短い待機期間を設けることでリスクを大幅に軽減できるとされています。
まとめ:npm installが怖くなった...でも大丈夫
今回のnpmサプライチェーン攻撃、正直めちゃくちゃ怖い話でしたが、
最新の情報にアンテナを貼ることと、
適切な知識と対策があれば、これらの脅威から身を守ることができます。
重要なポイントおさらい
- npm install = セキュリティリスクあり: 「ただのインストール作業」じゃないって認識が大切
- 継続監視が必要: 依存関係の変更を監視、怪しい動きには要注意
- スピード対応: 攻撃発覚時の対応手順を事前準備しておく
- 予防が最強: 認証情報の適切管理と環境分離
開発者として今日からできること
- 依存関係を意識的に管理する(なんとなくインストールしない)
- セキュリティ情報にアンテナを張る
- 適切なツールとプロセスを導入する
- チーム全体でセキュリティ意識を共有する
「完璧にやるの大変そう...」
でもこれは一度に全部やろうとせず、できることから少しずつ、「今」始めていかないといけない問題だと思います。
サプライチェーン攻撃はこれからもあり続けるので、僕たち開発者もできるだけ学んで対策をアップデートしていきましょう!
この記事の情報は2025年9月16日時点のものです。被害パッケージ数は継続的に増加しており、セキュリティ情報については、npmの公式発表やセキュリティ専門機関の情報を定期的にご確認ください。
新たなるメンバーを募集中!
少しでも気になる方はぜひ見てみてください!🔍