iimon TECH BLOG

iimonエンジニアが得られた経験や知識を共有して世の中をイイモンにしていくためのブログです

npmサプライチェーン攻撃の脅威と対策

1. はじめに

こんにちは!株式会社iimonでエンジニアをしている遠藤です。

AIが実在しないパッケージ名を提案する性質を悪用する「スロップスクワッティング(Slopsquatting)」という新しいタイプのサプライチェーン攻撃があることを最近知りました。
そこで本記事では、従来から存在するパッケージサプライチェーン攻撃とその対策を整理した上で、AIを活用する際に気をつけたいことについても学んだことをまとめていきます。

※ 本記事ではnpmを題材としますが、PyPIやRubyGemsなど他のパッケージレジストリを利用する場合にも同様のリスクがあります。

2. npmサプライチェーン攻撃の系譜

2-1. サプライチェーン攻撃とは

サプライチェーン攻撃とは、組織を直接攻撃するのではなく、その組織が依存している外部の仕組み(取引先、供給元、利用しているソフトウェアなど)を経由して攻撃する手法です。
今回取り上げるのはサプライチェーン攻撃の中でも「ソフトウェアサプライチェーン攻撃」に分類される攻撃手法です。ソフトウェアサプライチェーン攻撃とは、ソフトウェアの製造・配布工程に不正なコードが混入されるタイプの攻撃を指します。
攻撃者は、オープンソースコードのように標的が信頼して取り込む仕組みを悪用することで攻撃を行います。自分が使用しているパッケージ自体やパッケージの依存関係が侵害された場合、インストールや更新のタイミングで気付かぬうちに自分の環境も侵害される可能性があります。

2-2. 代表的な攻撃手法

悪意あるパッケージの新規公開

タイポスクワッティング

攻撃者は、人気パッケージの名前に似せた悪意あるパッケージをあらかじめ公開しておきます。開発者がパッケージをインストールする際にタイプミスをすると、本物ではなく悪意あるパッケージをインストールしてしまう、という仕組みです。例えば、lodash に対する loadash のように、一文字違いの悪意あるパッケージが登録されるケースがあります。タイプミス (typo) と不法占拠 (squatting) を組み合わせた造語で、元々はドメイン名を対象とした攻撃手法でしたが、現在ではパッケージレジストリにも応用されています。

ディペンデンシーコンフュージョン

2021年にセキュリティ研究者の Alex Birsan 氏が公開した攻撃手法で、Apple・Microsoft・PayPalなど35社以上の組織で報奨金プログラムの一環として実証されました。攻撃者は、組織が使用するプライベートパッケージと同じ名前で公開レジストリにパッケージを登録します。

medium.com

  • プライベートパッケージの名前は、ビルド成果物やGitHub上の package.json から漏洩しやすいこと
  • プライベートパッケージと同名のものが公開レジストリに登録されている場合、設定によっては公開レジストリ側のパッケージをインストールしてしまうこと

が指摘されています。
npmではこれを防ぐため、スコープ付きパッケージ (@org/package) の使用が推奨されています。

既存パッケージの改ざん

攻撃者は、メンテナーのパスワード漏洩や期限切れメールドメインの悪用によるアカウント乗っ取り、あるいは過去のevent-stream事件のようにメンテナンス引き継ぎを装ったソーシャルエンジニアリングなど、複数の手段を用いて既存の人気パッケージに悪意のあるコードを追加します。パッケージを利用している開発者が、その侵害されたバージョンをインストールすることで攻撃が成立します。

なお、アカウント乗っ取りを防ぐため、npmではメンテナーに対する2要素認証の義務化が段階的に実施されています。

2-3. 取り込まれた後の動作

悪意あるパッケージを取り込んでしまうと、インストール時やアプリケーション実行時に悪意あるコードが実行される可能性があります。

よくあるのが、npmの「ライフサイクルスクリプト」を悪用する攻撃です。package.json には "scripts" フィールドがあり、そこに書かれたコマンドをnpmが特定のタイミングで自動的に実行する仕組みがあります。
特に preinstallpostinstall は、パッケージが npm install された際に自動で実行されます。本来これは、インストール環境に合わせてバイナリを構築する等の正当な処理のために用意された仕組みで、例えば画像処理ライブラリの sharp は、内部で使用するネイティブライブラリ (libvips) の検出と、必要に応じたビルド処理を、インストール時のスクリプトで自動実行しています。
悪意あるパッケージは、この仕組みを攻撃に悪用します。さらに、この挙動は直接の依存だけでなく、依存の依存 (推移的な依存) でも同様に適用されるため、自分で直接インストールしていないパッケージのライフサイクルスクリプトであっても、インストール時に自動で実行されてしまいます。

他にも前述のevent-stream事件のように、パッケージのコードに悪意が仕込まれる場合もあります。この事件は悪意あるメンテナによって悪意ある依存が追加されたもので、Copay開発者がリリースビルドスクリプトを実行した際に悪意あるコードがCopayアプリ本体に注入され、その結果、Copayアプリを実行したエンドユーザーが被害を受ける二段階攻撃でした。 blog.npmjs.org

2-4. 起こり得る被害

ここまで紹介したように、悪意あるパッケージが取り込まれた場合、開発者の権限で任意のコードが実行される可能性があります。つまり、その環境でアクセスできる情報や操作できるものは、原理的にすべて悪用されうるということです。

具体的に想定されるリスクとしては、以下のようなものが挙げられます。

  • ファイルシステムへのアクセスによる、認証情報 (SSH鍵、トークン、.env ファイルに保存されたAPIキーなど) やソースコードの窃取
  • 外部からのマルウェアのダウンロード
  • バックドア (RATなど) の設置による永続的なアクセス権の確保

実際、2026年3月に発生したaxiosの侵害事件では、メンテナのnpmアカウントが乗っ取られて悪意あるバージョンが公開され、それをインストールした開発者の環境に、postinstallフックを通じてmacOS、Windows、Linuxで動作するマルウェアをダウンロードする仕組みが仕込まれていました。

www.trendmicro.com

被害は、取り込んだ開発者の環境にとどまらない場合もあります。窃取された認証情報が踏み台となり、組織のCI/CD環境やクラウドインフラにまで侵害が広がるおそれがあります。前述のevent-stream事件のように、開発者自身ではなくエンドユーザーが最終的な被害者になるケースもあります。

3. スロップスクワッティングとは

AIの台頭により新たなサプライチェーンの脅威と言われているのが「スロップスクワッティング」です。

LLMはハルシネーションによって実在しないパッケージ名を提案することがあります。攻撃者はLLMの挙動を観測し、繰り返し提案される架空の名前を特定します。そしてその名前で悪意あるパッケージを公開し、開発者がAIが提案したパッケージを盲目的に信頼してインストールするのを狙います。

2章で紹介したタイポスクワッティングは開発者のタイプミスを狙う攻撃でしたが、スロップスクワッティングはLLMのハルシネーションを狙う攻撃です。攻撃の入り口が「人間のミス」から「AIのミス」に変わっただけで、インストールされた後の挙動 (ライフサイクルスクリプトの悪用や認証情報の窃取など) は従来の攻撃と同じです。

socket.dev

4. 日頃の対策

4-1. インストール前にパッケージ情報を確認する

2章で紹介した偽物のパッケージ(タイポスクワッティングやスロップスクワッティング)に対しては、インストール前の確認が有効です。

公式サイトや公式ドキュメントで、インストールコマンドが一致しているかを確認します。特にAIが提案したパッケージ名は、実在するものか必ず確認する必要があります。

npmのパッケージページやGitHubリポジトリで以下の情報をチェックするのも参考になります。

  • 公開日や最終更新日
  • 週間ダウンロード数
  • メンテナの情報
  • GitHubリポジトリの有無とスター数、issueの対応状況

また、Socketのようなパッケージ分析ツールを使用するのも一つの手です。

ただし、これらの確認は偽物のパッケージを見分けるのには有効ですが、広く使われている信頼されたパッケージが乗っ取られるケース(axios事件のようなもの)や、大量の推移的依存の一つひとつには対応しきれません。後述する他の対策と組み合わせることが重要です。

なお、npm install <パッケージ名> を実行する際にタイプミスがないことも、タイポスクワッティング対策として重要です。

4-2. ライフサイクルスクリプトの実行を無効化する

プロジェクトの .npmrc やグローバルの ~/.npmrcignore-scripts=true を追加します。これによってnpm installを実行した際にpreinstallやpostinstallが実行されるのを防ぎます。
グローバルに設定しておくと、新しく触るプロジェクトでもデフォルトで保護されるので安心です。

nodejs.org

ただし正当な理由でライフサイクルスクリプトを実行しているパッケージもあるため、必要なときは npm rebuild <パッケージ名> で個別に実行するか、@lavamoat/allow-scripts のようなツールで「信頼するパッケージだけ許可する」運用が推奨されています。

また、pnpm や Bun など、デフォルトでスクリプトをブロックしてくれるパッケージマネージャを使うのも選択肢です。

4-3. すぐに新しいバージョンにアップグレードしない

古いバージョンを使用しつづけることは脆弱性につながりますが、最新のバージョンが常に一番安全とは限りません。むしろ最新のバージョンは、サプライチェーン攻撃にさらされていても、まだ検知されていない可能性があります。一定期間リリースされているパッケージであれば、コミュニティが問題を検出する時間ができるため、既存パッケージの改ざんへの対策としても有効です。

npm v11.10.0(2026年2月リリース)以降では、プロジェクトの .npmrc やグローバルの ~/.npmrcmin-release-age=7 のような設定を追加することで、指定した日数より新しいバージョンのインストールを拒否できます。
※お使いのnpmバージョンがv11.10.0以降であることを確認してください

2章で紹介したaxios事件のように、悪意あるバージョンが数時間で削除されるケースでは、数日のクールダウンを設けるだけでインストールを回避できます。
Dani Akash 氏の検証によれば、過去8年間の21件のサプライチェーン攻撃のうち、7日間のクールダウンで11件(約半数)の短命な攻撃をブロックできたとされています。
どの程度の期間を設けるかは組織の判断ですが、簡単に導入できる割に効果の高い対策と言えます。

daniakash.com

4-4. lockfile とバージョン固定

npm install 実行時に自動生成される package-lock.json には、実際にインストールされた各パッケージの具体的なバージョンが記録されます。このファイルをリポジトリにコミットしてチームやCI/CDで共有することで、いつ誰がインストールしても同じバージョンを再現できます。

特に CI/CD では npm install ではなく npm ci を使うことで、package-lock.json に記録された通りのバージョンが厳密にインストールされ、意図しないバージョンアップを防げます。

一度安全と確認したバージョンを固定することで、意図しないバージョンアップによる被害を防げる、クールダウン設定と補完的な対策です。

4-5. 継続的に依存関係を監視する

一度インストールしたパッケージも、後から脆弱性や侵害が発覚することがあります。定期的に依存関係を確認する仕組みを取り入れておくと安心です。

手軽な方法として、npm 標準の npm audit コマンドがあります。package-lock.json に記録された依存関係を既知の脆弱性データベースと突き合わせて、問題のあるパッケージを報告してくれます。

より継続的に監視するなら、GitHub の Dependabot や Snyk、Socket などのサービスを活用するのも一つの手です。これらは脆弱性のある依存を自動で検知して通知してくれたり、修正用のプルリクエストを自動で作成してくれたりします。

4-6. 認証情報を必要最小限に

ここまで紹介した対策を取っても、悪意あるパッケージをインストールしてしまう可能性を完全にゼロにすることはできません。そのため、万が一のときの被害範囲を小さく抑える備えも重要です。

  • ローカルに必要以上の認証情報を置かない.env に使っていないAPIキーが残っていたり、~/.aws/credentials に過去のプロジェクトの認証情報が残っていたりすると、侵害時にそれらがまとめて盗まれる恐れがあります。使わない認証情報はこまめに削除しておきましょう。

  • 使用する認証情報は用途ごとに権限を最小化する。GitHub のトークンや AWS のクレデンシャルなど、認証情報を発行する際は、必要な範囲やリソースにのみ権限を絞ります。万が一漏れても、攻撃者にできることを限定できます。

4-7. AI活用時の追加の注意

AIエージェントを使って開発する場合、特有のリスクとして「承認プロセスの煩わしさ」が挙げられます。
けれども、爆速で開発が進む中で、頻繁な確認に対して反射的に「yes」を返す習慣がついてしまうと、スロップスクワッティングのような攻撃を見逃す可能性が高まるので注意が必要です。

利用形態によらず、AIが提案してきたパッケージ名は、実在するか、公式ドキュメントに記載されているかをインストール前に確認することを徹底しましょう。

また、ローカルでCLIを使用する場合は、npm install のようなパッケージインストール系のコマンドは、AIエージェントで自動実行されないよう明示的に設定しておくと安心です。例えばClaude Codeなら、Deny ルールで実行自体をブロックしたり、Askルールで毎回確認を求めるように設定したりできます。

可能な作業であれば Claude Code on the Web のようなクラウド上の隔離された環境で実行されるAIエージェントを利用するのも良さそうかなと思いました。

www.anthropic.com

上記のブログによると、各セッションがクラウド上の隔離されたサンドボックス内で実行され、git認証情報や署名キーなどの機密情報はサンドボックス内には置かれない設計になっているため、万が一悪意あるコードが実行されてもローカルマシンや認証情報への影響を抑えられます。
ただし、ローカル環境にしかないツールやサービスに依存する作業には向かないので、作業内容に応じて使い分けると良さそうです。
なお、生成されたコードや成果物そのものに悪意が紛れ込んでいる可能性もあるため、インストールしているパッケージが正しいかの確認は引き続き必要です。

5. 発覚した場合の対応

悪意あるパッケージをインストールしてしまったと気付いたら、まずやることは以下の2つです。

  • パッケージのアンインストールと node_modules の削除(依存関係を一度リセットする)
  • 上司やセキュリティ担当者に報告する

迅速に報告して指示を仰ぎ、以降は会社のガイドラインに従って行動してください。

一般的には、

  • 影響範囲(いつインストールしたか、どのマシン・プロジェクト・CI/CD で実行された可能性があるか、 GitHubのセキュリティログ等)の確認
  • 影響を受けたマシン上の認証情報のローテーション(キーを無効化して再発行など)
  • マシンの再構築(OS再インストールやスナップショットからの復元)

といった対応が挙げられます。

6. まとめ

今回はnpmのサプライチェーン攻撃についてまとめてきました。
たった1行のコマンド実行で組織のインフラやエンドユーザーまで侵害される恐れがあると思うと怖すぎます。
サプライチェーン攻撃に限らず、開発者としてこういった脅威や対策は理解しておく必要があると感じました。
また、もしもの時のためにも、ローカルに置いている認証情報をちゃんと把握しておきたいところです。

実際にAIエージェントを使用していて偽物のパッケージを提案されたこともあるので、気を引き締めてAIとお付き合いしていきたい所存です!

最後まで読んでくださりありがとうございます!
記事の内容に誤りがありましたらご指摘いただけますと幸いです。

弊社ではエンジニアを募集しております。
ご興味がありましたらカジュアル面談も可能ですので、下記リンクより是非ご応募ください!
iimon採用サイト / Wantedly

参考

docs.npmjs.com

docs.npmjs.com

blog.npmjs.org

github.blog

www.anthropic.com

cheatsheetseries.owasp.org

nodejs.org

socket.dev

medium.com

sharp.pixelplumbing.com

www.trendmicro.com

guardian.jpn.com

www.cloudflare.com

www.sompocybersecurity.com

pnpm.io

www.trendmicro.com

daniakash.com