npm v12が今月リリースへ、サプライチェーン攻撃の温床だった「インストールスクリプト」をデフォルト無効化
2026年7月9日 18:42
JavaScriptのパッケージマネージャー「npm」の16年の歴史において、最も重要なセキュリティ刷新となる「npm v12」が、2026年7月末までに正式リリースされる見通しだ。v12では、これまでサプライチェーン攻撃の温床となっていたインストールスクリプトの自動実行がデフォルトで無効化され、明示的な「許可リスト制」へと移行する。すでに提供されているnpm 11.16.0の警告に対応せずにCI/CDパイプラインでnpm installを実行しているチームは、v12への移行と同時にビルドがサイレントに失敗する可能性があるため、早期の準備が求められている。
■サイレントなコード実行の温床だったインストールスクリプト
現在、開発者がNode.jsプロジェクトの依存関係をインストールするたびに、npmはアプリケーションコードが1行も実行される前に、依存関係ツリー内のすべてのパッケージに実行権限を与えている。パッケージは、ユーザーの完全な権限でサイレントに実行されるpreinstall、install、postinstallといったライフサイクルスクリプトを定義できる。平均的なnpmプロジェクトは、開発者が直接監査していない間接依存関係(トランジティブ依存関係)を79個も引き込んでおり、そのうちのどれか1つでも悪意のあるインストールスクリプトを含んでいる可能性がある。
GitHubのnpm v12チェンジログでは、これがnpmエコシステムにおける「単一で最大のコード実行サーフェス(攻撃対象領域)」と表現されている。実際に機能するためにインストールスクリプトを必要とするnpmパッケージは約2%にすぎず、大部分は明示的に実行可能なビルド手順の便宜的なショートカットとして使用している。しかし、現在のnpmのアーキテクチャでは、100%のパッケージがインストール時に任意のコードを実行する暗黙の権利を持っている。npm v12は、この98%の不要な実行サーフェスをデフォルトでゼロにする。
■npm v12の仕組み:実行時検出ではなくソース管理による許可リスト制
npm v12では、allowScriptsのデフォルト設定が「off」になる。開発者がnpm installを実行すると、パッケージマネージャーは依存関係のライフサイクルスクリプトを実行する前に、プロジェクトのpackage.jsonに明示的な許可リスト(allowlist)があるかどうかを確認する。許可リストに登録されていないパッケージのスクリプトは、サイレントにブロックされる。
これは、npmエコシステムが信頼を割り当てる方法における構造的な転換である。「公開されたすべてのパッケージは暗黙的にコード実行を許可される」という考え方から、「レビュー可能でバージョン管理された許可リストにあるパッケージのみがインストール時に実行できる」という考え方への移行だ。この許可リストはセッションフラグではなく、package.jsonに書き込まれ、ソース管理にコミットされ、プルリクエストで差分を確認でき、セキュリティチームが監査できるようになる。
また、許可リストモデルは、従来の回避策であった「--ignore-scripts」フラグでは対処できなかった2つの攻撃経路も遮断する。
1つ目は、Git依存関係の実行パスだ。npmがGitソースの依存関係をインストールする際、システムのgitバイナリを呼び出す。悪意のあるGit依存関係は、独自の.npmrcファイルを含めることでそのバイナリへのパスを上書きし、「git」を攻撃者が制御する実行ファイルに置き換えてインストール中に実行させることが可能だった(--ignore-scriptsが有効であっても実行された)。npm v12は、すべてのGit依存関係をデフォルトでブロックし、明示的な「--allow-git」フラグを要求する。
2つ目は、「Phantom Gyp(ファントム・ジップ)」攻撃だ。binding.gypファイルを含むパッケージは、ライフサイクルスクリプトの記述がなくても、npm install中にnode-gypの自動再ビルドをトリガーする。npmはこのファイルを持つパッケージをコンパイルが必要なネイティブアドオンとして扱い、無条件でビルドを実行する。多くのセキュリティスキャナーはアップロードされたパッケージのscripts.postinstallを監視しているため、攻撃サーフェスが157バイトのbinding.gypファイルである場合、検知をすり抜けてしまう。npm v12は、この暗黙のビルドトリガーを明示的なインストールスクリプトと同等に扱い、プロジェクトのallowScripts許可リストにパッケージが登録されていない限りブロックする。
さらに3つ目の変更として、HTTPSのtarballやその他のレジストリ外のソースといったリモートURL依存関係も、デフォルトで「--allow-remote=none」とすることでブロックする。
■検出技術の限界と許可リストモデルへの移行
npm v12の重要性は、単にデフォルト設定が変更されることだけに留まらない。許可リストモデルの導入は、パッケージ公開後のリアルタイム検出だけでは、悪意のあるパッケージの出現スピードに追いつけないという事実を、レジストリのデフォルトレベルで認めたことを意味する。セキュリティスキャナーの網羅性、SLSA(Software Supply Chain Levels for Software Artifacts)のプロベナンス(由来)証明、レジストリの審査プロセスはいずれも、2025年および2026年の攻撃ペースに対抗するには不十分であることが証明されている。
The Futurum Groupでソフトウェアライフサイクルエンジニアリングのプラクティスリードを務めるMitch Ashley氏は、「パッケージのインストールは、エコシステムのデフォルトレイヤーにおいて、暗黙の信頼から明示的な許可リスト制へと移行しつつある。自動スクリプト実行、Git解決、リモートフェッチをデフォルトで無効化することは、公開後の悪意のあるパッケージ検出が、その出現スピードに追いつけないことを認めるものだ。これからはエンジニアリングチームやプラットフォームチームが、ソース管理にコミットされた依存関係の許可リストを所有し、CIは未レビューのインストールスクリプトに対してビルドを失敗させなければならない。インストール時に何が実行されるかを検証することは、セキュリティチームの後知恵ではなく、エンジニアリングの常時義務となる」と指摘している。
なお、pnpmは2025年1月にリリースされたpnpm v10において、npmより18か月早くこれと同一のポリシーを実装していた。当時はNode.jsコミュニティから反発もあったが、その後、同期間にnpmプロジェクトを襲った攻撃からpnpmユーザーを守った実績として評価されている。Yarn BerryやBunもデフォルトでライフサイクルスクリプトをブロックしている。npmは、すべての依存関係に対してインストール時の暗黙の実行権限を与え続けていた、最後の主要なJavaScriptパッケージマネージャーだった。
■v12への移行を決定づけた3つの大規模攻撃
npm v12の導入タイミングは、インストール時の実行モデルが産業化された攻撃サーフェスであることを露呈させた3つのキャンペーンと直接結びついている。
1つ目は「Shai-Hulud」(2025年9月)だ。Palo Alto NetworksのUnit 42がnpm攻撃の「嫌がらせの時代」の終わりと評したこの自己複製型ワームは、被害環境からGitHubやnpmのパブリッシュトークンを盗み出し、パッケージを自動的に感染させて再パブリッシュした。最初の波だけで、chalkやdebugを含む180以上のパッケージが被害に遭い、これらの週合計ダウンロード数は26億回を超えていた。2026年の後続の波では約800パッケージに拡大し、Zapier、PostHog、Postmanに関連するプロジェクトにまで達した。
2つ目は「Axios」への攻撃(2026年3月31日)だ。北朝鮮の国家支援型攻撃グループ「Sapphire Sleet」(BlueNoroffやAPT38としても知られる)とされる攻撃者が、週に約1億回ダウンロードされるHTTPクライアントライブラリ「Axios」のリードメンテナーのnpmアカウントを乗っ取り、悪意のある2つのバージョンを公開した。Microsoft Security Blogの分析によると、攻撃者はAxiosのコードを直接変更するのではなく、postinstallフックを使用してクロスプラットフォームのリモートアクセス木馬(RAT)をドロップする「plain-crypto-js」という悪意のある依存関係を注入した。米国土安全保障省サイバーセキュリティ・インフラセキュリティ庁(CISA)は、影響を受けるバージョンをインストールしたシステムは完全に侵害されたものとして扱うよう推奨するアドバイザリを発行した。Huntressは、3時間の露出時間中に少なくとも135のエンドポイントが攻撃者のコマンド&コントロール(C2)インフラに通信したことを確認している。
3つ目は「Miasma」(2026年6月1日〜5日)だ。このキャンペーンは、オープンソース化されたShai-Huludのツール群をベースにした模倣犯によるもので、1か月あたり40万8000回ダウンロードされる「@vapi-ai/server-sdk」を含む57以上のnpmパッケージを侵害した。ここで使われた「Phantom Gyp」手法は、インストールスクリプトのスキャンに対する直接的な回答だった。攻撃者はpostinstallエントリの代わりに悪意のあるbinding.gypファイルを挿入し、標準的なセキュリティスキャナーを回避しながら、npmの暗黙のnode-gyp再ビルドをトリガーして攻撃者が制御するコードを実行させた。ペイロードはAWS、GCP、GitHub、Kubernetesの認証情報を収集し、アクセス可能なすべてのメンテナーアカウントから再パブリッシュすることで自己拡散した。
さらにMiasmaは、当時最高峰のサプライチェーン完全性検証とされていた「SLSAビルドレベル3」のプロベナンス証明をもバイパスした。ワームは正規のパイプラインの内部から動作していた。Red Hat従業員のGitHubアカウントが侵害され、本物のGitHub Actionsワークフローがトリガーされたことで、技術的に有効なプロベナンスを持つトロイの木馬化されたパッケージが公開された。SLSAはどのパイプラインがパッケージをビルドしたかを検証することはできるが、そのパイプラインの内部状態がクリーンであったかどうかまでは検証できない。
GitHubは、Miasmaの第2波の5日後に、npm v12の破壊的変更に関する予告を公開した。
■npm v12はこれらの攻撃をどう防げたか
npm v12のallowScriptsの変更は、Axios攻撃で悪用されたpostinstallの実行パスを直接遮断する。メンテナーのアカウントが侵害され、悪意のあるplain-crypto-js依存関係が公開されたとしても、v12を実行しているプロジェクトでそのパッケージが明示的に承認されていない限り、postinstallフックはブロックされる。
Phantom Gyp手法にも対処している。npm v12は、binding.gypファイルがトリガーする暗黙のnode-gyp再ビルドをブロックし、明示的なインストールスクリプトと同様に扱う。ネイティブコンパイルが必要なパッケージは、プロジェクトのallowScripts許可リストに登録されていなければならない。
また、「--allow-git」の変更により、--ignore-scripts下でも機能していた.npmrcの上書きパスが閉じられる。「--allow-remote」の変更により、検証不可能なtarballのURLがブロックされる。
一方で、セキュリティ研究者はv12が防げない領域についても指摘している。侵害されたメンテナーアカウントからレジストリに悪意のあるパッケージを公開することは依然として可能であり、その悪意のあるコードがライフサイクルスクリプトではなくパッケージの実行時(ランタイム)関数に存在する場合、それをインストールしてインポートした開発者には届いてしまう。OX SecurityのMoshe Siman Tov Bustan氏は、「アカウントの乗っ取りは依然として未解決の傷口だ。攻撃者が正規のメンテナーの認証情報を管理してしまえば、インストールスクリプトをどれだけブロックしても意味がない。悪意のあるコードは、信頼され署名されたリリースとして出荷されてしまうからだ」と述べている。タイポスクワッティング、依存関係の混乱(Dependency Confusion)、脆弱性を含んだ正規パッケージなどは、v12のデフォルト設定の対象外である。
■v12導入で発生する「サイレントなビルド失敗」への対策
npm v12への移行において最も危険なのは、エラーを吐いて派手に壊れるパッケージではなく、サイレントに壊れるパッケージだ。ネイティブアドオンパッケージがv12のallowScriptsデフォルト設定によってブロックされた場合、npm installは終了コード「0」でエラーメッセージを出さずに完了する。しかし、ネイティブバイナリはコンパイルされていないため、後から実行時に「cannot find module X.node」というエラーが発生し、インストール手順との関連性が一見して分からない形で表面化する。
このサイレント失敗の挙動は、終了コード「0」をビルド成功の指標としているCI/CDパイプラインにおいて特に危険だ。パイプラインは正常にパスするものの、初回実行時にクラッシュするデプロイメントが作成されてしまう。対策として、チームはCIコマンドに「--strict-allow-scripts」を追加し、終了コードだけに頼るのではなく、インストール後にネイティブモジュールを明示的にrequire()するスモークテストを記述すべきである。
最も一般的に影響を受けるのは、ネイティブアドオンを使用するパッケージだ。sharp(画像処理)、bcrypt(パスワードハッシュ化)、canvas、sqlite3、fsevents、bufferutil、esbuild、@tailwindcss/oxideなどは、インストール時のコンパイルやバイナリのダウンロードに依存している。また、Puppeteer、Playwright、Cypressなどのブラウザ自動化ツールは、postinstallを使用してブラウザのバイナリ全体をダウンロードするため、これらのダウンロードもブロックされる。推奨される回避策は、postinstallフックに頼るのではなく、npm installの後に「npx playwright install」や「npx cypress install」を明示的に呼び出すことだ。
モノレポ(Monorepo)構成を採用している場合は、さらに注意が必要となる。package.jsonのallowScriptsフィールドは、ワークスペースごとに個別にスコープが設定される。リポジトリのルートで承認しても、ネストされたパッケージには伝播しない。ネイティブ依存関係を含む各ワークスペースで、個別に「npm approve-scripts」を実行する必要がある。
バージョンが固定された許可リストは、意図的なセキュリティ機能である。以前に承認されたパッケージであっても、新しいバージョンにアップデートされた際にはその承認は引き継がれない。npm updateの後に承認を更新する必要があり、手間は増えるが、信頼されたパッケージの侵害されたバージョンが古い承認のまま実行されるのを防ぐことができる。
■7月末までに「npm approve-scripts」を実行する手順
GitHubは、v12のリリースを待たずに移行準備ができる滑走路を用意している。これら3つの変更は、すでにnpm 11.16.0において警告モードとして利用可能だ。スクリプトは依然として実行されるが、インストールのサマリーにおいて、v12でブロック対象となる未レビューのパッケージがすべてフラグ立てされる。
推奨されるワークフローは以下の4ステップだ。
1. npm 11.16.0以降にアップグレードする。これにより、ブロックを実行せずに警告モードを有効にできる。
2. 各プロジェクトで「npm approve-scripts --allow-scripts-pending」を実行する。これにより、v12でブロックされる予定のスクリプトやソースを持つ依存関係の完全なリストが生成される。ほとんどのアプリケーションでは、この段階で3〜8個のパッケージが表示される。
3. フラグが立った各パッケージをレビューし、インストール時の実行が本当に必要なものは「npm approve-scripts」で承認し、それ以外は「npm deny-scripts」で拒否する。許可リストはpackage.jsonに書き込まれる。
4. 更新されたpackage.jsonをソース管理にコミットする。開発者のマシンやCI環境で一貫して効果を発揮させるには、許可リストをバージョン管理する必要がある。
社内のHTTPS tarballに依存しているチームや、パッケージをGitブランチに固定しているモノレポの場合、すべてのCIスクリプトに「--allow-remote」を追加するのではなく、GitHub Packages、Nexus、Artifactoryなどの適切なレジストリに移行することが長期的な解決策となる。このフラグは正当なユースケースのために存在するが、全面的なオーバーライドとして使用するとセキュリティ上の意図が損なわれてしまう。
インストールスクリプトに依存しているパッケージのメンテナーは、この要件を明確にドキュメント化し、prebuild、prebuildify、node-pre-gypなどのツールを使用して事前ビルドされたバイナリを出荷することを検討すべきだ。インストールスクリプトへの依存を排除したパッケージは、それを悪用した攻撃の標的にならなくなる。
なお、v12以前の挙動を完全に復元したいチームは、.npmrcに「allow-scripts=all」を設定できるが、これはセキュリティ上のメリットを放棄することになるため推奨されない。
■許可リストを狙うソーシャルエンジニアリングへの警戒
許可リストモデルは、セキュリティチームが明示的に対処すべき新たな失敗モードをもたらす。CIで大量のv12警告に直面した開発者が、警告をすぐに消すために「npm approve-scripts --all」を実行してしまうリスクだ。これでは、各パッケージを慎重にレビューする代わりに無差別に承認することになり、システムの目的が完全に損なわれてしまう。
このリスクは仮定の話ではない。2026年のnpmサプライチェーン攻撃はすべてデフォルトの信頼モデルを悪用したものだった。v12はそのデフォルトを狭めるが、人間の意思決定レイヤーを排除するわけではない。承認プロセスが形骸化し、バックログを処理するためにすべての承認要求にラバースタンプ(盲目的な承認)を押すようになれば、承認サイクルの合間にパッケージを侵害した攻撃者に、アップデート時の実行パスを与えてしまうことになる。
組織的な対策として、最初のallowScriptsビルド時に個別のパッケージレビューを義務付けるポリシーを策定し、許可リストをコードレビューの対象に含め、承認待ちのスクリプトがあるパッケージが存在する場合はCIビルドを失敗させるように設定することが推奨される。
■注目ポイントQ&A
●npm v12にアップグレードすると、既存のプロジェクトは壊れますか?
ネイティブアドオンパッケージ(node-gypを使用しているものや、binding.gypファイルを含むもの)、Gitソースの依存関係、またはHTTPS tarballソースを使用しているプロジェクトは、準備なしにアップグレードすると破壊的変更の影響を受けます。インストールスクリプトを持たないレジストリパッケージのみに依存している純粋なJavaScriptプロジェクトは、問題なく移行できる可能性が高いです。影響を評価する最も早い方法は、npm 11.16.0にアップグレードしてnpm installを実行することです。表示される警告によって、v12で何がブロックされるかを正確に特定できます。また、「npm approve-scripts --allow-scripts-pending」を実行すると、変更を加えることなく完全なリストを生成できます。
●npm v12の許可リスト制によって、攻撃者が侵害されたパッケージを使ってできることはどのように変わりますか?
npm v12は、デフォルトの攻撃経路としてのpostinstallフック、binding.gypによるビルド、およびインストールスクリプトの自動実行を排除します。AxiosやMastraの侵害のように、悪意のあるペイロードがpostinstallフックを介して配信された攻撃に対しては、npm v12は、その依存関係を明示的に承認していないすべてのプロジェクトで実行をブロックしていたはずです。ただし、v12はパッケージの実行時(ランタイム)関数に埋め込まれた悪意のあるコード(インストール時ではなく、パッケージがインポートされたときに実行されるコード)からは保護できません。アカウントの乗っ取りは依然として深刻な課題であり、侵害されたメンテナーアカウントから公開された悪意のあるランタイムロジックを検出するメカニズムは、v12の許可リストにはありません。
●Phantom Gyp攻撃とは何ですか?なぜ標準的なスキャナーで検出できなかったのですか?
Phantom Gypは、攻撃者が侵害したパッケージに小さなbinding.gypファイルを追加する攻撃手法です。npmは、このファイルを含むパッケージをネイティブアドオンと解釈し、パッケージに明示的なインストールスクリプトの記述がなく、さらに「--ignore-scripts」が設定されていても、インストール中に自動的にnode-gyp rebuildを実行します。ほとんどのセキュリティスキャナーは、レジストリにアップロードされたpackage.jsonメタデータ内のscripts.postinstallを監視しているため、変更がbinding.gypファイルのみである場合はフラグを立てません。2026年6月のMiasmaワームの第2波では、インストールスクリプト検出を回避するためにこの手法が意図的に使用されました。npm v12は、この暗黙のbinding.gypビルドを、明示的なライフサイクルスクリプトと同様に許可リストによる承認が必要なものとして扱うことで、この経路を遮断します。
●移行を早く終わらせるために、チームで「npm approve-scripts --all」を実行してすべてを承認してもよいですか?
いいえ、推奨されません。一括承認は許可リストの目的を台無しにし、監査がより困難な形でv12以前の信頼モデルを再現してしまいます。許可リストのセキュリティ価値は、どのパッケージが本当にインストール時の実行を必要としているのかを理解し、パッケージごとに慎重にレビューすることから生まれます。まず「npm approve-scripts --allow-scripts-pending」を使用してリストを生成し、各パッケージを個別にレビューしてください。ほとんどのアプリケーションではリストは3〜8個のパッケージに収まるため、個別レビューは十分に現実的です。リストが膨大な場合は、ダウンロード数やメンテナーの履歴で優先順位をつけ、リスクの低いパッケージは初期移行後に2回目のレビューをスケジュールしてください。目標は、インストール時にコードを実行することが信頼されているパッケージをセキュリティチームが正確に把握できる、バージョン管理された成果物を作成することです。
元記事: npm v12 Ships This Month, Blocking Install Scripts That Enabled Year of Supply Chain Attacks