はじめに
2025年に複数回npmを標的としたサプライチェーン攻撃が発生しました。
8月のNx、9月のShai-Hulud攻撃に続き、11月末ごろにも同様の攻撃が発生しています。
今回の記事では、攻撃の概要と取り急ぎの対策、および今後開発者がどうやって攻撃に備えるべきかを考察します。
2025年8月 Nx(s1ngularity)攻撃
2025年8月26日、「s1ngularity」攻撃と呼ばれる悪意のあるNxパッケージによって引き起こされた大規模なサプライチェーン攻撃が発生しました。 発端はGitHub Actionsワークフローの脆弱性を突いて悪意のあるNxパッケージが数時間にわたり公開されたことです。
この攻撃により、Nxビルドシステムを利用していた多くの開発者の機密情報が盗まれ、さらに一部のユーザーのプライベートGitHubリポジトリが強制的に公開されるという被害も発生したと報告されています。
NxはJavaScript/TypeScriptのモノレポ管理ツールで、多くの企業で利用されています。実行タイミングとしてはpostinstallスクリプトで悪意のあるコードが実行される仕組みになっていました。postinstallについては後述します。
参考: Nx「s1ngularity」攻撃でAIはどのように利用されたか
2025年9月 Shai-Hulud攻撃①
攻撃者はnpmのメンテナの認証情報をフィッシング攻撃で盗み、アカウントを乗っ取って悪意のあるパッケージを更新した可能性が高いと言われています。
悪意のあるパッケージがnpm installなどでインストールされる際に実行されるスクリプトによってnpmトークンやGitHub PAT、ローカルの.envファイルなどに書かれたクラウドサービスの認証情報などが収集され、攻撃者に送信される仕組みになっていました。
npmトークンが盗まれることによって、感染した開発者が管理する別パッケージも改ざんしてpublishされてしまい、感染が指数関数的に増えたと言われています。
基本的な流れは以下の通りです。
-
改ざんされた正規パッケージが npm に公開される(メンテナのアカウント侵害などが前提)。
-
package.json に preinstall で setup_bun.js(または類似名)を起動するよう仕込まれる。
-
setup_bun.js が Bun ランタイムの有無を確認し、無ければインストールして実行環境を整える(正規のインストール手順に似せる)。
-
bun_environment.js(メインペイロード)が起動し、CI/CD 環境判定を行う。CIなら即時実行、開発者端末ならバックグラウンド化して「npm install が速く終わったように見せる」など、ステルス性を上げる挙動が報告されています。
-
GitHub / npm / AWS・GCP・Azure の認証情報やシークレットを探索・窃取し、公開 GitHub リポジトリ等へ流出させる。
-
盗んだトークンを使い、被害者が管理するパッケージへ 自動的にバックドア挿入→再 publishして自己増殖する。
2025年11月 Shai-Hulud攻撃②
11月末にも同様の攻撃が発生しました。こちらも同様にnpmメンテナのアカウントが乗っ取られ、悪意のあるコードが含まれたパッケージが公開されました。
攻撃の手法自体は9月の攻撃とほぼ同様ですが、攻撃コードはpreinstall段階で実行されるように仕込まれており、より早い段階で感染が広がる可能性がありました。
クラウドの認証情報の窃取に加えて、Secrets ManagerやKey Vaultなどの秘匿サービス経由で認証情報を取得しようとするコードも含まれていたようです。
また、破壊的挙動として、感染後攻撃に失敗した場合などにホームディレクトリを破壊するようなスクリプトが存在するという報告もあるようです。
preinstall/postinstallスクリプトとは
npmにはインストール時に自動実行されるスクリプト機構があり、Shai-Hulud攻撃ではこれを悪用しています。
- postinstall: パッケージのインストールが完了した直後に実行されるスクリプト
- preinstall: パッケージのインストールが始まる直前に実行されるスクリプト
基本的な仕組みとして、package.jsonのscriptsフィールドにbuildを書くと、npm run buildコマンドで実行できるようになります。加えてprebuildコマンドを定義すると、buildコマンドの前に自動的に実行されるようになります。
このような仕組みを利用するとpreinstallやpostinstallといった特別な名前をつけると、インストール時に自動的に実行されるようになります。
{
"scripts": {
"preinstall": "echo Preinstall script executed",
"postinstall": "echo Postinstall script executed"
}
}
考えられる被害まとめ
-
機密情報の漏洩
- CI/CD環境の認証情報の流出によって、改ざんされたコードが本番環境にデプロイされる
- 自分がメンテナンスしているnpmパッケージが改ざんされ、さらに感染を広げる
-
ホームディレクトリが破壊される
対策
取り急ぎの対策として、侵害の疑いが少しでもあれば、感染していない端末からnpmトークンやGitHub PAT、クラウドの認証情報をローテーションすることが重要です。
該当攻撃を受けているかどうかの確認として、複数の分析結果から、setup_bun.jsやbun_environment.jsといったファイル名が使われていることが多いようです。これらのファイルが含まれているパッケージをインストールしていないか確認することも有効です。
rg -n "setup_bun\.js|bun_environment\.js|set_bun\.js|shai[-_ ]?hulud|POSTINSTALL_BG|bundle\.js" \
package-lock.json pnpm-lock.yaml yarn.lock node_modules .github/workflows -S
新しいpublic repositoryとして、Shai-Huludを説明文に含むパッケージが勝手に作られていないかも確認しておきましょう
予防・再発防止への考察
サプライチェーン攻撃によって攻撃者にメリットのあることを考えておくと対策の方法が見えてきます。
任意の処理が実行できますが、多くの場合、機密情報や認証情報を盗む、データを壊したり、ロックをかけて身代金を要求するなどが主な目的になります。
被害者に気づかれない場合はリソースを仮想通貨のマイニングに使うなども考えられます。
コンテナでの開発
OSSでは混入経路がどうであれ、一定のリスクを背負っており、攻撃を完全に防ぐことは困難です。
開発者としては感染への完全な予防よりも、感染してもリスクを抑える方向にシフトすることが重要です。
その代表的な対策として、開発環境をコンテナ化する方法があります。
自分のPC上でのスクリプト実行の場合、.envなどのファイルだけでなく、普段利用しているDesktopフォルダなどにもアクセスできてしまいます。
開発環境を丸ごとコンテナなどの技術によって仮想化することで、ホストOSへの影響を抑えることができます。代表的な技術としてVirtualBoxやDocker、DevContainersなどがあります。
lockファイルの利用
PHPにおいてはComposer、JavaScriptエコシステムにおいてはpackage-lock.jsonやyarn.lock、pnpm-lock.yamlなどのロックファイルを利用することがサプライチェーン攻撃に対しては基本的な対策になります。
サプライチェーン攻撃においては、ある日突然、依存パッケージの最新版が汚染されることが多いため、最新の依存をインストールし続けるよりも、ロックファイルを用いた運用の方が依存の更新タイミングをコントロールできるため、安全性が高まります。
npmの場合はpnpmを検討する
npmに限った対策ですが、pnpmを利用することで攻撃の可能性を少し減らすことができます。
いわゆるゼロデイ攻撃と呼ばれるまだ公になっていない攻撃に対しては修正が間に合わない可能性が高く、防御的な仕組みを利用することが重要です。
pnpmの場合はminimumReleaseAgeを設定することで、公開から一定時間が経っていないバージョンはインストールをしない、という設定が可能です。
例えばShai-Hulud攻撃の場合は攻撃から発覚まで数日間でした。悪意のあるパッケージは多くのケースで公開から数日以内にコミュニティなどで発見されています。その後、セキュリティパッチなどによって修正されます。
数日間のバッファを作ることで多少ゼロデイ攻撃のリスクを減らすことができると言えます。
また、ignore-scriptsオプションを利用することで、preinstall/postinstallスクリプトの実行自体を抑止することも可能です。
本来スクリプトが必要なパッケージについてはホワイトリスト形式での許可ができるため、より安全に実行することができます。
