npm install を1回叩いただけで、依存ツリーの奥深くにあるパッケージの postinstall が任意のコードを実行する——これがこの10年間、Node.jsエコシステムの「仕様」だった。便利さと引き換えに、この挙動は認証情報を盗むマルウェアの最短経路にもなってきた。2026年7月にリリースが見込まれるnpm v12は、この前提を反転させる。install scriptはデフォルトで実行されなくなり、明示的に許可(opt-in)したパッケージだけが走る方式に変わる。
これは「歴史的大改革」といった煽りで語るべき話ではなく、パッケージマネージャーのデフォルトが安全側に倒れる、影響範囲の広い変更だ。すでにpnpmは2025年に、Bunはそれ以前から同じ方向へ舵を切っており、npmは業界の流れに追随した格好になる。問題は、あなたのプロジェクトやCI/CDが「暗黙にinstall scriptへ依存していた」場合、v12でビルドや実行が静かに壊れうる点にある。この記事では公式のGitHub Blogとnpm CLIドキュメントを一次ソースに、何が変わり・自分の環境はどう確認し・どう段階的に移行するかを実務目線で整理する。
サプライチェーン攻撃そのものの全体像と防御ツールの体系は、当メディアのまとめ記事 サプライチェーンセキュリティ完全ガイド2026|攻撃手法・防御ツール・実践チェックリスト にまとめてある。本記事はその中でも「npm v12という具体的な仕様変更に、開発チームとしてどう備えるか」に絞って掘り下げる。
この記事のポイント
- npm v12(2026年7月リリース見込み)は
preinstall/install/postinstallをデフォルトで実行しない。許可したいパッケージだけをpackage.jsonのallowlistに載せる方式へ変わる。 node-gypの暗黙リビルド(binding.gypを持つネイティブモジュール)も止まる。git依存・リモートURL依存も--allow-git/--allow-remoteの明示が必要になる。- まず
npm approve-scripts --allow-scripts-pendingで「どのパッケージがscriptを持っているか」を壊す前に予測できる。これがチームで最初に叩くべきコマンド。 - 移行は「警告で棚卸し → allowlist作成 → package.jsonにコミット」の3ステップ。CI/CD・モノレポ・Docker・PaaSはいずれも同じ制約を受ける。
GitHub Actions経由で2349件の資格情報漏洩 2025-09 : Shai-Hulud 初波
自己増殖するnpmワーム・CISA緊急勧告 2025-11 : Shai-Hulud 第2波
再来と拡大 2026-03 : axios改ざん
RAT配布・週1億DLの依存 2026-05 : Mini Shai-Hulud
@antv 323パッケージを22分で汚染 2026-06 : GitHub公式が v12 の破壊的変更を予告
npm 11.16.0 で警告開始 2026-07 : npm v12 リリース見込み
install script デフォルトOFF
30秒でわかる:npm v12のpostinstall無効化
先に結論だけ押さえたい人向けに、要点を圧縮する。
・変わること:npm install 実行時、依存パッケージの preinstall / install / postinstall が既定で走らなくなる。
・代わりの仕組み:実行を許したいパッケージを package.json のallowlistに明示する。npm approve-scripts が対話的に許可、npm deny-scripts が拒否を記録する。
・巻き添えになるもの:binding.gyp を持つネイティブモジュールの暗黙 node-gyp rebuild、git依存の prepare、リモートURL(httpsのtarball)依存。これらも既定で止まる。
・いつ来るか:v12は2026年7月にリリース見込み。npm 11.16.0以降ではすでに警告が出始めている。
・まず何をするか:npm approve-scripts --allow-scripts-pending を叩き、自プロジェクトで許可待ちになるパッケージを一覧化する。
ここまでで「自分のプロジェクトは影響を受けるのか?」を知りたくなるはずだ。答えはほぼ確実にYesである。sharp・bcrypt・better-sqlite3・esbuild・puppeteer・playwright など、ネイティブビルドやバイナリ取得を伴う人気パッケージはinstall scriptに依存している。フロントエンドでもバックエンドでも、これらのいずれか1つも入っていないプロジェクトの方が珍しい。だからこそ「壊れてから気づく」のではなく、リリース前に棚卸ししておく価値がある。
誰が影響を受けるか(早見)
- ネイティブモジュール(sharp / bcrypt / better-sqlite3 / node-sass など)を使う全プロジェクト。
- Puppeteer / Playwright などブラウザバイナリを取得するE2Eテスト環境。
- git依存(
"pkg": "github:org/repo")やリモートtarball依存を持つプロジェクト。 - Dockerでネイティブビルドしているイメージ、およびそれをデプロイするCI/CD。
「壊れる」ときの具体像も先に知っておくと落ち着いて対処できる。典型は次の3パターンだ。1つ目はビルドは成功するのに実行時にネイティブバイナリが見つからないケース(sharpやbetter-sqlite3など、暗黙リビルドが止まった結果)。2つ目はE2Eテストがブラウザバイナリ不在で起動しないケース(Puppeteer/Playwrightの取得scriptが走らなかった結果)。3つ目はgit依存やリモートtarball依存が「見つからない」で解決に失敗するケース。いずれも「npm installは通ったのに、その後で失敗する」という遅延した壊れ方をするのが厄介で、原因がv12のデフォルト変更だと気づきにくい。だからこそ事前の棚卸しが効く。
何が変わるのか:install scriptのデフォルトOFFとallowlist方式
ここからは公式のGitHub Blog changelogとnpm CLIドキュメントを根拠に、変更の中身を正確に見ていく。
v11までの挙動(現状)
現行のnpm v11では、npm install は依存パッケージの preinstall / install / postinstall を自動的に実行する。これを止める唯一の全体スイッチが --ignore-scripts で、公式ドキュメントは「trueにするとpackage.jsonに指定されたスクリプトを実行しない」と定義している。ただしこれは「全部止める / 全部動かす」の二択で、粒度がない。ネイティブビルドが必要なパッケージまで一律で止まるため、--ignore-scripts を常用すると別の場所でビルドをやり直す運用が要る。
つまり現状は「デフォルトで全許可、嫌なら全拒否」という極端な設計だった。この間に、任意コード実行の入口として postinstall が繰り返し悪用されてきた。
なぜinstall scriptが攻撃の入口になるのか
postinstall が狙われる理由は、攻撃者にとっての「実行タイミングの良さ」にある。開発者やCIが npm install を実行した瞬間、そのスクリプトは開発者本人の権限で走る。手元のマシンなら ~/.aws/credentials やSSH鍵、環境変数に載ったトークンに手が届き、CI上ならビルドシークレットやOIDCで取得したクラウド権限に届く。しかも依存ツリーは深くネストしていて、直接インストールした覚えのない孫・ひ孫パッケージが数百単位でぶら下がる。そのどれか1つが改ざんされれば、npm install 1回で発火する。
この構造は「信頼の推移律」の問題でもある。あなたが信頼しているのは直接依存の数十パッケージだが、実際に自マシンでコードを実行できるのは推移的依存を含めた数百〜数千パッケージだ。npm v12のデフォルト変更は、この「暗黙に広がった実行権限」を、明示的に許可した範囲まで縮める操作にあたる。allowlistは単なる設定ファイルではなく、「誰にコード実行を託したか」を可視化する信頼の台帳になる。
v12の挙動(デフォルトOFF + allowlist)
GitHub公式の予告によれば、v12では npm install が依存パッケージの preinstall / install / postinstall を、プロジェクトで明示的に許可しない限り実行しなくなる。「デフォルト全許可」から「デフォルト拒否・opt-inで許可」への反転だ。許可の管理は次のコマンド群で行う。
# 許可待ち(scriptを持つが未許可)のパッケージを一覧化する
npm approve-scripts --allow-scripts-pending
# 信頼するパッケージのscript実行を許可する(対話的に選択)
npm approve-scripts
# 残りのパッケージを明示的に拒否として記録する
npm deny-scripts
approve-scripts / deny-scripts の結果は package.json に書き込まれ、バージョン管理に乗る。これが設計上の肝で、「どのパッケージにコード実行を許したか」がコードレビュー可能な差分として残る。チームの誰かがallowlistに新しいパッケージを足せば、それはPRのdiffに現れ、レビューで止められる。
node-gyp・git・リモート依存も止まる
見落としやすいのが、明示的なinstall scriptを書いていないパッケージも巻き添えになる点だ。公式は、binding.gyp を持つだけで明示的なinstall scriptがないネイティブパッケージも、npmが暗黙に走らせる node-gyp rebuild ごとブロックされると明言している。sharpやbetter-sqlite3のようなC/C++バインディングは、この暗黙リビルドでバイナリを用意していた。v12ではこれが止まるため、「ビルドは成功したのに実行時にネイティブバイナリが見つからない」という形で表面化しうる。
さらに次の2つも既定で拒否される。
・git依存:"pkg": "github:org/repo" のようなgit由来の依存は、--allow-git(既定 none)を明示しない限り解決されない。git依存の prepare スクリプトも同様に止まる。
・リモートURL依存:httpsのtarballを直接指す依存は、--allow-remote(既定 none)を指定しない限りブロックされる。
| 項目 | npm v11(現状) | npm v12(2026-07見込み) |
|---|---|---|
| install script既定 | 自動実行(全許可) | 実行しない(opt-in許可制) |
| 許可の粒度 | --ignore-scripts で全拒否のみ |
パッケージ単位のallowlist |
| 許可の保存先 | なし | package.json(レビュー可能) |
| node-gyp暗黙rebuild | 走る | allowlist未登録なら止まる |
| git依存 | 解決される | --allow-git 明示が必要 |
| リモートURL依存 | 解決される | --allow-remote 明示が必要 |
| 主なコマンド | --ignore-scripts |
approve-scripts / deny-scripts |
ここで誤解しやすい点を1つ明確にしておく。デフォルト無効になるのは依存パッケージのライフサイクルスクリプトであって、あなた自身のプロジェクトの package.json に書いたscriptは対象外だ。npm run build や npm test、あるいはあなたが自分のリポジトリのルートに書いた postinstall は、これまで通り動く。止まるのはあくまで node_modules にインストールされてくる第三者パッケージのinstall scriptである。この線引きを理解していないと「自分のビルドスクリプトまで動かなくなるのか」と過剰に身構えてしまうが、実際に棚卸しが必要なのは第三者依存の側だけだ。同様に、npm start のように明示的にscriptを実行するコマンドは、名前で指定している以上そのまま実行される。v12が変えるのは「頼んでいないのに勝手に走る」部分に限られる、と捉えると全体像がクリアになる。
なぜ今このタイミングか:postinstall攻撃の系譜
npmがこの決定に至った背景には、この1年で連続した現実の攻撃がある。ここでは各インシデントを、CISA勧告・GitHub Security Advisory・一次分析レポートなど公式に近いソースの事実だけで1〜2行ずつ振り返る(誇張や物語化はしない)。
・2025-08 Nx「s1ngularity」:nxパッケージが改ざんされ、悪性コードがGitHub Actionsのビルドパイプライン内で実行された。Wizの分析では合計2,349件の秘密情報(GitHubトークン・クラウド認証情報・NPMトークンなど)が漏洩し、攻撃者はAIコマンドラインツールを偵察に悪用していた。
・2025-09 Shai-Hulud(初波):postinstall を使って自己増殖する初のnpmワーム。500以上のパッケージに拡散し、CISAが緊急勧告を出した。感染環境からクラウド資格情報とトークンを収集する。
・2025-11 Shai-Hulud(第2波):同系統の攻撃が再来・拡大し、npmエコシステムの構造的な脆さを改めて示した。
・2026-03 axios改ざん:週1億ダウンロード規模のaxiosにマルウェアが混入し、3プラットフォーム対応のRATが配布された。証拠を自動削除する高度な手口で、OpenAIの内部ビルドにも波及した(詳細は当メディアの過去記事参照)。
・2026-05 Mini Shai-Hulud(@antv):メンテナアカウント乗っ取りで @antv 系の可視化ライブラリ323パッケージがわずか22分で汚染された。AWS・GitHub・Kubernetesなど20種類超の認証情報を狙う。
これらに共通するのは、「インストール時に任意コードが走る」という前提が攻撃の初動を成立させていた点だ。ワームの自己増殖も、認証情報の収集も、最初の一歩は postinstall などのライフサイクルスクリプトである。npm v12のデフォルト変更は、この「最初の一歩」そのものを既定で塞ぐという発想に立っている。
もう一つ見逃せないのは、攻撃の頻度と速度が上がっている点だ。Mini Shai-Huludは323パッケージを22分で、Nx Consoleの事案は最大6000件超をわずか11分で汚染した。人間が気づいてから対応するまでの時間より、汚染が広がる時間の方が短い。この非対称性の前では、「怪しいパッケージを事後に検知する」だけの防御には限界がある。発火の起点であるinstall scriptを既定でオフにしておくことは、検知が間に合わない現実に対する構造的な回答だ。裏を返せば、npm v12以降も「allowlistに載せたパッケージ」は依然として任意コードを実行できるため、許可の判断そのものの質が新たな防御ラインになる。デフォルトが安全側に倒れることで、開発者が本当に注意を向けるべき対象が「全パッケージ」から「自分が明示的に信頼したパッケージ」へと絞り込まれる——これがv12がもたらす実務的な変化の本質だ。
関連する具体的インシデントは当メディアでも一次ソースをたどって解説している。CI/CDの依存更新経路そのものを守る観点は Renovate・Dependabotのサプライチェーン攻撃対策、実際の大規模汚染の技術的全容は @antv npmのMini Shai-Hulud事案 と Nx Console 18.95.0の認証情報窃取事案 を合わせて読むと、v12が「なぜこの設計になったのか」の解像度が上がる。
自システムで確認する4つのコマンド
ここが本記事の核だ。リリース後に慌てないために、いま手元のプロジェクトで叩けるコマンドを4つ用意した。いずれも破壊的な操作ではないので、そのままコピペして影響を先読みできる。
コマンド1:現行のnpmバージョンを確認する
まず自分のnpmが今どこにいるかを知る。11.16.0以降なら、すでに警告が出る状態だ。
npm --version
# 11.16.0 以降なら approve-scripts 系のコマンドと警告が使える
コマンド2:許可待ちパッケージを予測する(最重要)
v12で「許可が必要になる」パッケージを、壊す前に一覧化するコマンドがこれだ。チームで最初に共有すべき出力になる。
# scriptを持つが未許可のパッケージ(=v12で止まる候補)を列挙
npm approve-scripts --allow-scripts-pending
出力に並ぶパッケージが、v12移行後にallowlistへの登録判断が必要になる対象だ。ここに見覚えのないパッケージが混じっていれば、それ自体がサプライチェーン監査のきっかけになる。
コマンド3:postinstallを持つパッケージを洗い出す
npm本体の機能に頼らず、node_modules を直接調べて postinstall を宣言しているパッケージを列挙する。CIログに残しておくと差分監視にも使える。
# node_modules配下でpostinstallを宣言しているpackage.jsonを列挙
find node_modules -name package.json -maxdepth 3 \
-exec grep -l '"postinstall"' {} \;
コマンド4:暗黙リビルド対象(binding.gyp)を洗い出す
明示的なscriptを書いていなくても止まる、node-gyp暗黙リビルド対象を可視化する。sharpやbetter-sqlite3のようなネイティブ依存がここに出る。
# node-gypの暗黙rebuild対象になるネイティブパッケージを列挙
find node_modules -name binding.gyp
CIで「移行後に何が壊れるか」を先読みするワンライナー
CIのジョブに次のステップを一時的に足すと、v12相当の挙動(scriptを全部止めた状態)でビルドが通るかを事前検証できる。落ちたパッケージが、allowlist登録の第一候補になる。
# クリーンな状態でscriptを止めてinstallし、影響を観測する
rm -rf node_modules
npm ci --ignore-scripts && npm run build \
|| echo "⚠ script依存あり: このビルドはv12でallowlist登録が必要"
出力の読み方:3つの分類で仕分ける
4コマンドの出力は、次の3グループに仕分けると判断が速い。
・必須・信頼できる(許可):sharp・bcrypt・better-sqlite3・esbuild・puppeteer・playwright など、ビルドや実行に不可欠で広く使われている公式パッケージ。これらは approve-scripts で許可する。バイナリ取得やネイティブビルドが目的で、スクリプトの存在自体が正当だ。
・不要・惰性で入っている(拒否か除去):かつて使っていたが今は参照していない、あるいはより軽量な代替がある依存。deny-scripts で拒否するか、そもそも依存から外せないかを検討する。allowlistを機に依存の棚卸しをするのは健全だ。
・見覚えがない(要調査):直接インストールした記憶がなく、名前もタイプミス的(例:正規パッケージに1文字違いで似せたもの)なパッケージ。これはtyposquattingや依存混乱攻撃の兆候かもしれない。安易に許可せず、レジストリでメンテナと公開履歴を確認する。
重要なのは、この仕分けをリリース前の平時にやっておくことだ。障害対応の最中に「とりあえず全部許可」で切り抜けると、悪性パッケージの許可がそのままコミットされ、v12の恩恵を自ら捨てることになる。allowlistの初期作成は、時間に余裕のあるスプリントで済ませておきたい。
この4コマンドは、Aikidoをはじめとするセキュリティベンダーのブログでは深掘りされていない「自分のプロジェクトを具体的に測る」ための実務ステップだ。ベンダー製品を入れる前に、まず現状把握のコストがゼロで済むのが利点である。
移行手順とCI/CD・モノレポ・Dockerへの影響
移行は3ステップで考えると迷わない。「①警告で棚卸し → ②allowlist作成 → ③package.jsonにコミット」だ。判断の流れは次の図に集約される。
技術的な手順そのものは軽いが、実際のチームで詰まるのは「誰がいつ、どのパッケージの許可を判断するのか」という運用側だ。allowlistへの追加は一種のセキュリティ判断なので、担当を曖昧にするとレビューが形骸化する。おすすめは、初回の棚卸しをセキュリティに明るいメンバーとリードエンジニアの二人体制で行い、その結果を「なぜこのパッケージを許可したか」の短いメモとしてリポジトリに残すことだ。sharpやbcryptのような自明なものは一行で済むが、社内公開パッケージや珍しい依存については、公開元・メンテナ・用途を書き添えておくと、半年後に「これ何のために許可したんだっけ」と迷わずに済む。allowlistは一度作って終わりではなく、依存を追加・更新するたびに育てていく生きたドキュメントだと捉えるとよい。この運用が根づけば、v12は単なる制約ではなく、チームの依存管理を成熟させるきっかけになる。
で許可待ちを一覧化] --> B{そのパッケージは
信頼できるか?} B -->|公式・広く使われ
ビルドに必須| C[approve-scripts で許可
package.json に記録] B -->|不要 or 出所不明| D[deny-scripts で拒否
依存自体の見直しも検討] C --> E[package.json の allowlist を
コミットしてレビュー] D --> E E --> F[CI/CD で --ignore-scripts 相当を検証] F --> G{ビルド/テストは
通るか?} G -->|Yes| H[移行完了] G -->|No| A
ステップ1〜3:警告 → allowlist → コミット
ステップ1(警告で棚卸し):npm 11.16.0以降にアップデートし、npm approve-scripts --allow-scripts-pending で許可待ちを洗い出す。ここで出たリストがそのまま作業対象になる。
ステップ2(allowlist作成):npm approve-scripts を対話的に実行し、ビルドに必須で信頼できるパッケージだけを許可する。出所不明・不要なものは npm deny-scripts で拒否として記録する。「なんとなく全部許可」は、この変更の意味を無にするので避ける。
ステップ3(コミット):allowlistが書き込まれた package.json をコミットし、PRでレビューする。運用ルールとして「allowlist行の追加はレビュー必須・自動マージ対象外」を決めておくと、悪性パッケージの許可登録が無審査で通るのを防げる。
移行のタイミングと切り戻し
v12は破壊的変更なので、いきなり本番CIのnpmをv12に上げるのは避けたい。現実的な順番は、まずnpm 11.16.0以降で警告を観測する期間を設け、その間にallowlistを整備してコミットしておくことだ。allowlistは前方互換で、v11環境でも package.json に書かれているだけでは害がない。つまり「v12に上げる前にallowlistを先にコミットしておく」ことで、実際のバージョンアップを安全なタイミングまで遅らせられる。
切り戻しの観点も押さえておく。もしv12化後にビルドが壊れたら、恒久対応はallowlistの追記だが、一時的な緊急回避としてはnpmのバージョンをv11系にピン留めして時間を稼げる(package.json の engines やCIのsetup-nodeのバージョン指定、Dockerのベースイメージタグで固定する)。ただしこれはあくまで時間稼ぎであり、allowlistの整備を先送りにする言い訳にはしない。警告期間のうちに棚卸しを終えていれば、この緊急回避に頼る場面はほぼ来ない。
CI/CD:GitHub Actions・CircleCI・GitLab CI
CI/CDは内部でnpmを呼ぶだけなので、npmがv12になれば同じ制約を受ける。allowlistを package.json にコミットしてあれば設定変更は基本不要だが、移行検証のジョブを1つ足しておくと安全だ。GitHub Actionsなら次のようなステップを一時的に入れて、script無効状態でビルドが通るかを確認する。
# .github/workflows/ci.yml(移行検証用の一時ステップ例)
- name: Verify build without install scripts (v12 dry-run)
run: |
npm ci --ignore-scripts
npm run build
# 落ちたら package.json の allowlist を見直す合図
CircleCIやGitLab CIでも考え方は同じで、npm ci の前段に --ignore-scripts での検証ジョブを差し込む。恒久対応はあくまで package.json のallowlistであり、--ignore-scripts は「v12相当の状態を再現する検証スイッチ」として使うのがよい。
モノレポ・Docker・PaaSの注意点
・モノレポ(pnpm workspaces / Turborepo / Nx):allowlistはinstallを実行する単位の package.json に書き込まれる。ルート集中管理ならルートに集約、パッケージ個別installなら各所に分散する。どこにallowlistが存在するかをREADMEに明記しておくとチームが迷わない。
・Docker:RUN npm ci はallowlist未登録パッケージのscriptを実行しないため、ネイティブビルドが必要なら実行時に「バイナリが無い」で落ちうる。allowlistを含む package.json とlockファイルを先に COPY してからinstallする構成で、レイヤーキャッシュと再現性を両立させる。
・PaaS(Vercel / Netlify / Cloudflare Pages):ビルドは内部のnpmに従うだけなので、事前にallowlistをコミットしておけば設定変更なしで通る。各PaaSのNode.jsランタイム更新でnpmがv12に上がる時期を把握しておくとよい。
代替・補完アプローチの比較
npm v12を待たずに、あるいはv12と併用して「install時の任意コード実行」を抑える方法は複数ある。1つの製品に一本化する必要はなく、環境に合わせて組み合わせるのが現実的だ。ここが「Safe Chain一択」で語られがちな論点との差になる。
| アプローチ | 仕組み | 粒度 | 位置づけ |
|---|---|---|---|
| npm v12 allowlist | script既定OFF + package.json許可 | パッケージ単位 | 標準の恒久対策(2026-07〜) |
npm ci --ignore-scripts |
全scriptを一律停止 | 全体のみ | 旧来のハードOFF・検証用 |
pnpm onlyBuiltDependencies |
v10で既定OFF + allowlist | パッケージ単位 | npmの先例。すでに実運用 |
Bun trustedDependencies |
既定OFF + 信頼リスト | パッケージ単位 | 更に前からの前例 |
| yarn(Berry) | dependenciesMeta.<pkg>.built で個別制御 |
パッケージ単位 | 既定は実行寄り・設定で制御 |
| Safe Chain(Aikido) | install前にパッケージを走査・遮断 | スキャン単位 | 補完的な検知レイヤーの一つ |
| Renovate / Dependabot | 依存更新の自動化と可視化 | PR単位 | 更新経路の監視(別レイヤー) |
注目すべきは、npm v12が「業界初」ではないことだ。pnpmは2025年のv10でライフサイクルスクリプトを既定で無効化し、pnpm.onlyBuiltDependencies によるallowlistと pnpm approve-builds を導入済みである(きっかけはRspackのサプライチェーン攻撃だった)。さらにBunはそれ以前から trustedDependencies による信頼リスト方式を採っており、pnpmはこれを先行事例として参照していた。npm v12は、この2つが実証したモデルをエコシステム最大のパッケージマネージャーに持ち込む、という位置づけになる。
そのうえで各アプローチは排他ではない。恒久対策としてnpm v12(またはpnpm/Bun)のallowlistを土台にしつつ、--ignore-scripts はCIでの移行検証スイッチとして、Safe Chainのような走査ツールは「許可済みパッケージが後から改ざんされた場合」の検知レイヤーとして、Renovate/Dependabotは更新経路の可視化として、それぞれ別の穴を塞ぐ。多層防御の観点では、デフォルトを固める(v12)× 変化を監視する(更新自動化)× 中身を走査する(スキャン)の3方向を持つのが理想だ。
どう選ぶか:チーム規模別の指針
現実には全部を一度に導入する必要はない。チームの状況に応じて優先順位をつけるとよい。
・個人・小規模プロジェクト:まずはnpm v12(またはpnpm/Bun)のデフォルトに乗るだけで、投資ゼロで大きな守りが手に入る。allowlistのコミットさえ習慣化すれば十分な出発点になる。追加ツールは後回しでよい。
・中規模の開発チーム:allowlistの運用ルール(追加はレビュー必須)をCIに組み込みつつ、Renovate/Dependabotで更新経路を自動監視する。ここまでで「許可の可視化」と「変化の検知」の2軸が揃う。
・大規模・規制業界:上記に加えて、Safe Chainのようなインストール前スキャンや、内部ミラーレジストリでの承認フローを重ねる。許可済みパッケージが後から乗っ取られる「時間差攻撃」まで想定するなら、走査レイヤーの価値が出てくる。
ここで強調したいのは、どの規模でも土台は「デフォルトの堅牢化」だという点だ。高価な検知ツールを入れても、npm install が任意コードを無条件で走らせる前提のままでは穴は塞がらない。v12(やpnpm/Bun)が提供するのは、その最も基礎的で効果の大きい土台である。ベンダー製品はその上に積む補完であって、代替ではない。
まとめ:v12は「守りのデフォルト」への静かな移行
- npm v12の本質は派手な新機能ではなく、
npm installのデフォルトが安全側に倒れること。既存プロジェクトは「暗黙のscript依存」を棚卸しする必要がある。 - 今日できるのは3つ:①
npm --versionで現行確認、②npm approve-scripts --allow-scripts-pendingで影響予測、③package.jsonのallowlistをPRレビュー対象として運用に組み込む。 - pnpm・Bunという先例があるため、移行の型はすでに枯れている。焦らず「警告 → allowlist → コミット」の3ステップで進めればよい。
参照ソース
- GitHub Blog: Upcoming breaking changes for npm v12(公式・一次ソース)
- npm CLI公式ドキュメント: npm install(
--ignore-scripts/--foreground-scripts) - CISA Alert: Widespread Supply Chain Compromise Impacting npm Ecosystem(Shai-Hulud, 2025-09-23)
- Wiz Blog: s1ngularity supply chain attack(Nx, 2025-08)
- Socket.dev: pnpm 10.0.0 Blocks Lifecycle Scripts by Default
- Aikido Security(本テーマを最初に取り上げた海外記事・参考)