プログラミング セキュリティ 公開日 2026.09.11 更新日 2026.10.24

npm installは通るのに依存のバージョンが上がらない|overridesが上流の修正を打ち消す

フレームワークのセキュリティ修正版に上げたのに、修正の本体である下位の依存が古いまま残ることがあります。原因は自分で書いたoverridesで、上流が引き上げた下限を打ち消してしまうためです。npmとpnpmの両方で再現した結果と、どのコマンドなら気づけるかを実測でまとめます。

目次(18項目)

先に要点

  • overrides は依存の要求を置き換える機能です。上流が「この版以上でないと危険」と要求を引き上げても、自分が書いた古い範囲がそれを消してしまい、ロックの古い版が据え置かれます。
  • 筆者が npm と pnpm の両方で再現しました。上流が 0.35.4 以上を要求するようになっても、overrides が 0.35.0 以上のままだとロックは 0.35.3 から動きません。npm install は正常終了し、npm outdated にも何も出ません。
  • 気づける道具はあります。npm audit はこの状態を high として検知し、npm audit fix は override を越えて 0.35.4 まで上げました。つまり危険なのは「install が通ったから直った」と判断することです。
  • もう1つ測って分かったこと。overrides はローカル参照(リンクされる依存)には効きません。同じ設定でも、リンクかパッケージ本体かで結果が変わります。

フレームワークのセキュリティ修正版が出たので上げた。npm install も通った。これで対応は終わり、と考えるのが自然です。ところが、修正の本体である下位の依存だけが古いまま残ることがあります。

原因は自分の package.json に書いた overrides です。過去に何かの理由で足した1行が、上流のセキュリティ修正を打ち消してしまう。この記事では、その仕組みを手元で再現した結果と、どのコマンドなら気づけるのかを整理します。

何が起きるのか

overrides(pnpm では pnpm.overrides)は、依存の依存のバージョンを指定する機能です。npm の公式ドキュメントは「依存ツリーの中のパッケージを、別のバージョンや別のパッケージに置き換える」機能だと説明しています。用途の例として「既知のセキュリティ問題があるバージョンを置き換える」ことが挙げられています。

つまり本来はセキュリティのための機能です。ところが「置き換える」がそのまま罠になります。置き換えるということは、上流のパッケージが書いた要求が消えるということです。

よくある流れはこうです。

よくある流れ
  1. 1

    overrides を書く

    何かの事情で overrides に「この依存は 0.35.0 以上」と書いた。

  2. 2

    ロックに 0.35.3 が入る

    当時の最新は 0.35.3 だったので、ロックには 0.35.3 が入った。

  3. 3

    脆弱性が見つかる

    数か月後、その依存に深刻な脆弱性が見つかり、0.35.4 で修正された。

  4. 4

    上流が要求を引き上げる

    上流のフレームワークが「0.35.4 以上が必要」と要求を引き上げた修正版を出した。

  5. 5

    npm install する

    フレームワークを上げて npm install した。

ここで期待するのは 0.35.4 への更新です。実際にはロックは 0.35.3 のまま動きません。自分の overrides が「0.35.0 以上」と言っており、0.35.3 はその条件を満たしているからです。上流の「0.35.4 以上」という要求は、override に置き換えられて存在しません。

自分の overrides:0.35.0 以上 上流の要求:0.35.4 以上(消える) 0.35.0 0.35.3 0.35.4 ロックは 0.35.3 のまま override の条件を満たすので動かない

手元で再現する

検証した環境は Node.js 22.22.0 / npm 10.2.4 / pnpm 10.34.4 です。上流のパッケージ役として、依存に sharp を持つだけの小さなパッケージを作り、要求するバージョンを途中で引き上げました。

{
  "name": "ovtest",
  "private": true,
  "dependencies": { "needs-sharp": "./needs-sharp-1.0.1.tgz" },
  "overrides": { "sharp": "^0.35.0" }
}

ロックだけを作り直すコマンドで、4つの段階を順に流します。

npm install --package-lock-only

結果です。npm と pnpm で完全に同じ挙動でした。

段階 上流の要求 自分の overrides ロックの結果
1. 脆弱性が出る前 0.35.0 以上 0.35.3 に固定 0.35.3
2. 固定をやめて範囲に戻す 0.35.0 以上 0.35.0 以上 0.35.3
3. 上流が修正版を出した 0.35.4 以上 0.35.0 以上 0.35.3 のまま
4. overrides を直す 0.35.4 以上 0.35.4 以上 0.35.4

段階3が問題の状態です。上流は「0.35.4 以上でなければ危険」と言っているのに、ロックは 0.35.3 のままで、インストールは何事もなく完了します。

ここが見落としの起点

「overrides にセキュリティ対応として書いたのだから、この依存は管理できている」という認識が、そのまま逆に働きます。書いた当時は正しく、時間が経って上流が先に進んだ結果、同じ1行が更新を止める側に回ります。書いた本人ほど疑いません。

どのコマンドなら気づけるか

段階3の状態で、手元のコマンドが何を言うかを1つずつ確かめました。

コマンド 段階3での出力 気づけるか
npm install 正常終了 気づけない
npm outdated 何も表示されない(終了コード0) 気づけない
npm audit high 1件を検知。勧告IDとリンクつき 気づける
npm audit fix override を越えて 0.35.4 へ更新 直せる

npm audit の出力はこうなりました。1行目には対象が「0.35.4 未満」であることが不等号で表示されます。

Severity: high
sharp: Vulnerabilities in libheif ... - https://github.com/advisories/GHSA-rgj7-g3m4-5g8c
fix available via `npm audit fix`
node_modules/sharp

1 high severity vulnerability

ここは重要なので言い方を正確にします。スキャナが見落とすわけではありません。脆弱性の検査は正しく動きます。危険なのは、インストールが通ったことを「対応済み」の根拠にしてしまう判断の方です。

npm install の末尾には脆弱性の件数も出るのですが、更新作業の最後は出力が長く、成功して安心した直後でもあります。この1行を見落とす前提で、別の場所に検査を置くのが現実的な対策になります。

実際にあった例

2026年8月末、この形が実際に起きました。画像処理ライブラリ sharp が内部で使う libheif に脆弱性が見つかり、信頼できない AVIF 画像を処理すると、条件によっては遠隔でコードを実行されうるという勧告が出ています(GHSA-rgj7-g3m4-5g8c、深刻度 high、CVSS 8.9、修正版 0.35.4)。

これを受けて、画像最適化にこのライブラリを使うフレームワーク側にも勧告が出ました。Next.js の勧告(GHSA-2xp9-vwfh-vxw4、深刻度 critical、CVSS 9.5)は、原因を「Next.js が画像最適化に使う sharp の、その下の libheif の脆弱性」と明記し、修正が依存を通じて行き渡るまでの暫定措置として AVIF の最適化を無効化したと書いています。修正版は 15.5.24 と 16.3.3 です。

勧告が上流へ伝わった順番
  1. 1

    libheif に脆弱性

    信頼できない AVIF 画像を処理すると遠隔でコードを実行されうる。

  2. 2

    sharp の勧告

    深刻度 high、CVSS 8.9。修正版 0.35.4。

  3. 3

    Next.js の勧告

    深刻度 critical、CVSS 9.5。暫定措置として AVIF の最適化を無効化。修正版は 15.5.24 と 16.3.3。

つまりフレームワーク側の修正の実体は、下位ライブラリの下限を引き上げることでした。この構図のとき、自分の overrides がその下限より緩いと、フレームワークを上げても穴は塞がりません。フレームワークのバージョンだけを見て確認を終えると見逃します。

自分のプロジェクトを点検する

やることは単純で、override に書いた範囲が、上流が今要求している範囲を下回っていないかを確かめるだけです。

まず override の一覧を出します。

node -e "const p=require('./package.json'); console.log(p.overrides || (p.pnpm && p.pnpm.overrides) || 'なし')"

次に、それぞれの依存について、実際にロックに入っている版と、上流が要求している版を比べます。

npm ls sharp
npm audit

判断の基準は1つです。override に書いた下限が、上流の要求より古いなら、その override は更新を止めています。危険かどうかは別として、意図した状態ではありません。

下限は上流に合わせる

override を書くときは、その時点の最新ではなく「なぜその下限なのか」を書ける値にします。理由を書けないなら、そもそも override が不要な可能性があります。

不要になったら消す

override の多くは一時しのぎです。上流が追いついたら消します。残しておくと、この記事の状態に必ず入ります。

検査を別の場所に置く

インストールの出力ではなく、CI の独立したステップや定期実行で脆弱性検査を回します。人が長い出力を読む前提にしないのが要点です。

直接の依存には override を書けない

npm の公式ドキュメントには、もう1つ知っておくべき制限があります。自分が直接依存しているパッケージには、原則として override を書けません。指定が完全に一致していない限り、EOVERRIDE というエラーで止まります。

EOVERRIDE に当たったら

これは意地悪な仕様ではなく、同じパッケージについて依存の宣言と override の宣言が食い違う状態を作らせないためのものです。直接依存なら、dependencies の側を直せば済みます。実際、更新作業の途中でこのエラーに当たったら、override を消して依存の方を上げるのが正しい対応になります。依存と同じ指定にそろえたいときは、公式ドキュメントにある "$パッケージ名" の参照も使えます。

ローカル参照には overrides が効かない

再現を作る過程で、もう1つ測れたことがあります。ローカルのディレクトリを参照する形の依存には、overrides がまったく効きませんでした。

最初、検証用の小さなパッケージをディレクトリ参照で入れていました。この形だと依存はリンクとして扱われ、override を 0.35.1 のような明確に違う値にしても、解決結果は最新の 0.35.4 のまま変わりません。同じ内容をパッケージの塊として参照する形に変えたところ、override が正しく適用されました。

参照の形で override の効き方が変わる

ディレクトリ参照

リンクとして扱われる

注意点
  • override を 0.35.1 にしても 0.35.4 のまま

パッケージの塊として参照

パッケージ本体として扱われる

向いている点
  • override が正しく適用された

実務で効くのは、モノレポのようにローカル参照が混ざる構成では、override の効き方が場所によって変わるという点です。「書いたのに効いていない」と「書いたせいで止まっている」は正反対の症状ですが、どちらも override を読んだだけでは分かりません。判断は必ずロックか、実際に入っているものを見て行います。

もう1つ、公式ドキュメントには、overrides はプロジェクトのルートの package.json に書いたものだけが考慮され、ワークスペースや依存パッケージの中に書いたものは解決に影響しないと書かれています。モノレポでは、override をどこに書いたかも確認します。

関連して、ロックファイルそのものの役割はロックファイルとはに、パッケージマネージャーごとの違いはpnpmとはにまとめています。

よくある質問

overrides は使わない方がよいのですか

そうではありません。上流がまだ修正版を出していないのに、下位の依存にだけ修正版がある、という状況では override が唯一の手段になります。問題は書くことではなく置きっぱなしにすることです。書いた理由と、いつ消せるかをコメントか記録に残しておけば、この記事の状態は避けられます。

なぜ npm は警告してくれないのですか

npm から見れば、指示どおりに動いているだけだからです。override は「上流が何と言おうと、この範囲にする」という明示的な指示です。その結果として上流の要求が満たされなくなっても、それは利用者が選んだ状態だと解釈されます。だから検知はバージョン解決ではなく、脆弱性検査の側が担当します。

CVSS が高ければ必ず危険ということですか

CVSS は深刻度の目安であって、自分の環境で到達可能かどうかとは別です。たとえば今回の勧告は「信頼できない AVIF 画像を処理させられること」が前提なので、外部から画像を受け取る経路が無ければ実際の危険度は下がります。ただし到達しないことを理由にバージョンを上げない判断は勧めません。構成が変われば到達しうるためで、優先度を下げる根拠にはなっても、放置する根拠にはなりません。

pnpm や yarn でも同じですか

pnpm では同じでした。この記事の4段階を pnpm 10.34.4 でも流し、npm と完全に同じ結果になっています。yarn にも同種の機能(resolutions)があり、依存の要求を置き換えるという性質は共通なので、同じ形の見落としは起こりえます。「置き換える機能である」という一点さえ押さえていれば、道具が変わっても判断は同じです。

まとめ

overrides は依存の要求を置き換えます。置き換えるということは、上流が引き上げた下限も消えるということです。

  • 上流がセキュリティ修正で下限を上げても、override が緩ければロックは古いまま動かない
  • npm install も npm outdated も、この状態を教えてくれない
  • npm audit は検知し、npm audit fix は override を越えて更新する
  • 危険なのはスキャナの見落としではなく、インストールが通ったことを対応済みの根拠にする判断
  • ローカル参照の依存には override が効かないなど、書いた内容と実際の解決結果はずれる。必ずロックか実物を見て確かめる

更新作業の完了条件を「コマンドが成功したこと」ではなく「実際に入っている版を見たこと」に変えるだけで、この種の見落としはほぼ消えます。

参考リンク

あとで見返すならここで保存

読み終わったあとに残しておきたい記事は、お気に入りからまとめて辿れます。