フロントエンド

Node.jsのセキュリティリリースをきっかけに、放置していたNext.js 13を片付けた話|Next.js 15.5・swiper 14への更新とDependabotの設定

2026年10月21日、Node.jsのセキュリティリリースが公開されました。Highが4件含まれる、それなりに重いリリースです。

ちょうど、2023年に作ってからほぼ放っておいた個人サイト(Next.js 13のPages Router)があったので、これを機に対応しました。やってみると、Node本体の話だけでは終わらず、npm auditでcriticalが2件見つかったり、ライブラリの更新で見た目が崩れたりと、いろいろ出てきました。

この記事の内容は2026年10月時点のものです。

この記事では、その対応の流れを順番にまとめます。

  • Node.jsのセキュリティリリースに対して、実際に何をすればいいのか
  • npm auditでcriticalが出たNext.js 13とswiper 10の更新
  • 更新後に起きた、swiperの矢印が二重に表示される問題の直し方
  • 再発を防ぐためのDependabotの設定

脆弱性の中身と、コンテナで動かしているサイトでの確かめ方は Node.jsの2026年10月のセキュリティリリースに、Cloud RunのNext.jsでどう対応したか にまとめています。

対象のプロジェクト

項目 内容
フレームワーク Next.js 13.5.3(Pages Router)
主なライブラリ React 18、react-leaflet 4、swiper 10、sass
ホスティング Vercel
package.jsonの状態 nextやreact、eslintなどが"latest"指定
Nodeの版の指定 なし(.nvmrcもenginesもない)

create-next-appで作ったままの"latest"指定が残っていて、Nodeの版もどこにも書かれていない、よくある状態です。

Node.jsの2026年10月のセキュリティリリース

修正版は次のとおりです。

リリースライン 修正版
26.x v26.12.1
24.x(LTS) v24.22.1
22.x v22.23.4

主な脆弱性は、Brotliの展開処理でのリモートでのコード実行のおそれ、TLSのホスト名の検証のすり抜け、dns.resolveがNULを含む名前を切り詰める問題などです。詳しくは 公式の告知 を見てください。

サポートが終わった版(EOL)は、セキュリティリリースのたびに「常に影響を受ける」扱いになります。修正版は出ないので、サポート中の版に上げるしかありません。

ポイント:Node本体の脆弱性はnpm iでは直らない

最初に押さえておきたいのがここです。

今回の脆弱性はNode.jsのランタイムそのもの にあります。npmパッケージの脆弱性ではないので、package.jsonを書き換えたり、npm iし直したりしても直りません。

やるべきことは2つです。

  1. 実際にNodeを動かしている環境を、修正版に上げる(ローカルのMac、Vercelなどの本番環境、CI)
  2. プロジェクトに、使うNodeの版を書いておく(環境ごとの版のずれを防ぐため)

対応1:Node 24を使うよう、プロジェクトに明記する

どの版にするか

候補は22、24、26の3つでしたが、24(LTS) にしました。

  • 22は2027年4月でサポートが終わるので、今から選ぶ理由がない
  • 24はこれからメンテナンスの期間(セキュリティの修正だけ)に入り、2028年4月までサポートされる
  • 26は2026年10月にLTSになったばかり。Next.js 13が26で動くかは確かめていない。古いNext.jsを新しすぎるNodeで動かすほど不具合のリスクが上がるので、26への移行はNext.jsの大きな更新と一緒にやることにした

Node.jsはこれまで「偶数版だけがLTSになり、奇数版は半年ほどで終わる」という決まりでした。ただ、27からは年に1回のリリースになり、すべての版がLTSになると公式に発表されています。26が今の方式で出る最後の版です。次に上げる先は26、その次は2027年10月にLTSになる27、と考えておけば大丈夫です。

.nvmrcとenginesを足す

package.jsonにenginesを足します。

{
  "private": true,
  "engines": {
    "node": "24.x"
  }
}

Vercelはengines.nodeを見て、ビルドと実行に使うNodeのメジャー版を決めます。パッチ版はVercel側で自動的に最新が当たるので、24.xと書いておけば、再デプロイで修正版に切り替わります。

ローカル用に、プロジェクトの直下に.nvmrcも置きます。

24

これで、このフォルダでnvm installやnvm useと打つだけで、24系が選ばれます。

.nvmrcにパッチ版まで書くべきか

最初は24.22.1とパッチ版まで書いていましたが、24だけに変えました。

書き方 良いところ 気をつけるところ
24.22.1 修正版より古いものを使わないことを保証できる セキュリティリリースのたびに手で書き換える必要がある。忘れると古い版で固定される
24 nvm installを打てば、その時点の24系の最新が入る。ファイルの書き換えが要らない どのパッチ版が入っているかは、各自がnode -vで確かめる必要がある

個人のプロジェクトなら、24のほうが扱いやすいと思います。次に上げるときは、.nvmrcの24とenginesの24.xの2か所を書き換えるだけです。

ローカルのNodeを上げる

まず今の版を確かめます。

node -v

v24.22.1以上ならそのままで大丈夫です。それより古ければ、.nvmrcを読ませてインストールします。

nvm install
nvm use
node -v

最後のnode -vでv24.22.1以上になっていれば完了です。

動くかの確認

Next.js 13.5.3をNode 24でビルドして起動し、すべてのページとAPIルートが200を返すことを確かめました。Next.js 13.5のenginesは>=16.14.0で、Node 24でも問題なく動きました。

npm iではなくnpm ciを使う

依存パッケージを入れ直すときに迷ったのがここです。

このプロジェクトはnextやreactが"latest"指定になっています。この状態でnpm iすると、lockfileに書かれた版から上がってしまうことがあり、最悪Next.js 16まで一気に上がって壊れるおそれがあります。

npm ciなら、package-lock.jsonに書かれた版をそのまま入れます。node_modulesも自動で消してから入れ直してくれるので、「Nodeだけ上げて、依存パッケージはそのまま」という今回のような作業ではnpm ciが安全です。

npm ci
npm run build
npm run dev

対応2:npm auditのcriticalを消す

Nodeの対応のついでにnpm auditを実行してみたところ、こうなりました。

critical: 2, high: 6, moderate: 2(計10件)

criticalはnext 13.5.3とswiper 10でした。

Next.js:15.5系に上げる

Next.js 13.5.3には、たくさんの脆弱性がたまっていました。criticalのものは次の3件です。

内容 条件 直った版
Middlewareの認可のすり抜け Middlewareで認可をしている 13.5.9
Image Optimization APIでのリモートでのコード実行 AVIFの画像を使っている 15.5.24(16系は16.3.3)
リモートでのコード実行 Windowsでサーバーを動かしている 15.5.24(16系は16.3.3)

VercelはLinuxで動いているので、Windowsの件は当てはまりません。それでも、13系の最後の版(13.5.11)に上げても後ろの2つは直らないので、15.5.24以上にすることにしました。

最新はNext.js 16ですが、16に上げるにはReact 19が必要です。地図の表示に使っているreact-leaflet 4はReact 18専用で、React 19に上げるならreact-leaflet 5への更新も要ります。影響の範囲が一気に広がります。

そこで、React 18のまま使える最新の修正版として、15.5系の15.5.28を選びました。Next.js 15は、Pages RouterならReact 18に対応しています。

swiper:14に上げる

swiperのcriticalはプロトタイプ汚染で、12.1.2以上 で直っています。10から3つのメジャー版を上げることになりますが、使っている機能がNavigationとScrollbarだけだったので、最新の14.3.0にしました。

"latest"指定をやめる

今回の更新で、"latest"指定はすべてやめました。"latest"のままだと、npm iしたタイミングで、勝手にメジャー版が上がってしまうからです。

   "dependencies": {
     "leaflet": "^1.9.4",
-    "next": "latest",
+    "next": "15.5.28",
     "next-sitemap": "^4.2.3",
-    "react": "latest",
-    "react-dom": "latest",
+    "react": "^18.3.1",
+    "react-dom": "^18.3.1",
     "react-leaflet": "^4.2.1",
-    "sass": "^1.68.0",
-    "swiper": "^10.3.1"
+    "sass": "^1.106.0",
+    "swiper": "^14.3.0"
   },
   "devDependencies": {
     "@types/leaflet": "^1.9.6",
-    "@types/node": "latest",
-    "@types/react": "latest",
-    "@types/react-dom": "latest",
-    "eslint": "latest",
-    "eslint-config-next": "latest",
-    "typescript": "latest"
+    "@types/node": "^24.19.2",
+    "@types/react": "^18.3.31",
+    "@types/react-dom": "^18.3.7",
+    "eslint": "^8.57.1",
+    "eslint-config-next": "15.5.28",
+    "typescript": "^5.9.3"
+  },
+  "overrides": {
+    "postcss": "^8.5.23"
   }

nextとeslint-config-nextは、版を固定(--save-exact)しています。@types/reactもReact 18に合わせて18系に、eslintは今の.eslintrc.jsonをそのまま使えるように8系にしています。ESLint 8はすでにサポートが終わっているので、次に大きく更新するときに9系へ移すつもりです。

インストールは次のように行いました。

npm i --save-exact next@15.5.28 eslint-config-next@15.5.28
npm i react@^18.3.1 react-dom@^18.3.1 swiper@^14.3.0
npm i -D @types/react@^18.3.0 @types/react-dom@^18.3.0 @types/node@^24 eslint@^8.57.1 typescript@^5

残った脆弱性への対応

この時点でcriticalは0件になりましたが、highがいくつか残りました。

postcss:Next.js 15は内部でpostcssを8.4.31に固定していて、これが脆弱な版でした。overridesで新しい版を強制しています。

"overrides": {
  "postcss": "^8.5.23"
}

sass:古いsassがchokidar 3経由でbracesに依存していたので、最新の1.106に上げました。sassは1.79以降、bracesに依存しないchokidar 4を使っています。

そのうえで、npm audit fix(--forceなし)を実行して、自動で直せるものを直しました。

npm audit fix

最後まで残ったbracesの件

最終的に、highが7件残りました。

critical: 2 → 0
全体: 10件 → 7件

残った7件は、すべてbracesというパッケージのアドバイザリが原因でした。ESLintとnext-sitemap(サイトマップの生成)という、ビルドのときにしか動かないツールの中だけで使われていて、公開しているサイトのコードには含まれません。実害はほぼないと判断して、そのときは残しました。

その後、このアドバイザリは 取り下げ(Withdrawn) られました。今npm auditを実行するとfound 0 vulnerabilitiesです。

ただし、GitHubのDependabot alertsには、取り下げられたあとも「Withdrawn Advisory: braces vulnerable to stack-exhaustion denial of service …」というタイトルで、開いたままのアラートが残ることがあります(別のリポジトリで実際に残っていました)。取り下げられたアドバイザリなので、理由を付けて閉じて(Dismiss)大丈夫です。

npm auditは「0件にすること」が目的ではありません。「どこで使われていて、実際に影響があるか」を見て判断するのが大事だと、あらためて思いました。

動作の確認

Node 24で、次の点を確かめました。

  • npm run buildとnpx tsc --noEmitが通る
  • lintの警告は、以前からある2件だけ
  • すべてのページ、APIルート、sitemap.xmlが200を返す

対応3:swiperの矢印が二重に表示される

ローカルで確かめたところ、動作には問題がありませんでした。ただ、スライダーの矢印ボタンの中に 小さい「>」がずれて表示されている ことに気づきました。

原因

swiperは11から、ナビゲーションのボタンの中に矢印のアイコン(SVG)を自動で入れる ようになりました。

一方、このサイトではglobals.cssで.swiper-button-next::afterなどを使って、独自の矢印を描いていました。swiper 10までは、ボタンの中身はCSSの疑似要素で描く前提だったので、これで問題なかったのです。

その結果、独自の大きい矢印と、swiperが自動で入れた小さい矢印が重なって表示されていました。

直し方

swiperの自動のアイコンをオフにするオプションaddIconsがあるので、これをfalseにします。

 <Swiper
   modules={[Navigation, Scrollbar]}
   spaceBetween={50}
   slidesPerView={1}
   allowTouchMove={false}
-  navigation
+  navigation={{ addIcons: false }}
   scrollbar={{
     draggable: true
   }}
 >

これで元の矢印だけが表示されるようになりました。独自の矢印を使っているサイトでswiperを11以降に上げるときは、気をつけておきたいところです。swiperの基本的な使い方は Swiperの使い方 にまとめています。

対応4:Dependabotで再発を防ぐ

今回の脆弱性は、「何年も放っておいたから、たまった」ものです。"latest"指定もやめたので、放っておくとまた古くなります。そこで、GitHubのDependabotを設定しました。

Dependabot alertsとsecurity updatesをオンにする

リポジトリのSettings → Advanced Security(古い画面では「Code security and analysis」)で、次の2つをオンにします。

  • Dependabot alerts:package-lock.jsonの中に脆弱性が見つかると、通知が来る
  • Dependabot security updates:脆弱性の修正版があれば、更新のプルリクエストを自動で作ってくれる

公開のリポジトリでも、非公開のリポジトリでも、無料で使えます。

dependabot.ymlで、定期的な更新も自動にする

脆弱性がなくても定期的に更新のプルリクエストを作らせるため、.github/dependabot.ymlを足しました。

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
      day: "monday"
      time: "09:00"
      timezone: "Asia/Tokyo"
    open-pull-requests-limit: 5
    ignore:
      - dependency-name: "*"
        update-types: ["version-update:semver-major"]
    groups:
      minor-and-patch:
        applies-to: version-updates
        update-types:
          - "minor"
          - "patch"
    commit-message:
      prefix: "deps"

設定の意図は次のとおりです。

  • 毎週月曜の朝9時(日本時間) に確かめる
  • マイナー版とパッチ版は、1つのプルリクエストにまとめる(毎週何本も届かないように)
  • メジャー版の更新は除く(Next.js 16やReact 19への更新は、計画を立てて手で行う)

注意点

メジャー版を除く設定は、security updatesにも効きます。 今回のswiperのように、直すのにメジャー版の更新が必要な脆弱性は、プルリクエストが自動では作られません。ただし、アラートの通知は届くので、気づくことはできます。

また、DependabotはNode.js本体の版は見ていません。 今回のようなNodeのセキュリティリリースは、Node.jsのブログ などで別に確かめる必要があります。

おまけ:Private vulnerability reporting

同じ設定の画面に、「Private vulnerability reporting」という項目もあります。これはDependabotとは別の機能で、オンにすると、第三者がリポジトリの脆弱性を非公開で報告できる窓口 ができます。

  • Securityのタブに「Report a vulnerability」のボタンが表示される
  • 報告はIssueのように公開されず、自分と報告者だけが見られるセキュリティアドバイザリの下書きとして届く
  • 非公開でやり取りして直し、必要なら直したあとに公開できる

オンにしない場合、脆弱性に気づいた人が公開のIssueに書いてしまい、直す前に弱点が誰でも見られる状態になることがあります。デメリットはほぼないので、公開のリポジトリならオンにしておいて問題ないと思います。

まとめ

  1. Node本体の脆弱性は、実行環境のNodeを上げないと直らない。 .nvmrcとenginesで版を明記しておくと、ローカルと本番のずれを防げる
  2. Node.jsは27から、すべての版がLTSになる。 今は24か26、その次は27と考えておく
  3. "latest"指定のプロジェクトで依存パッケージを入れ直すときはnpm ci。 npm iだと、意図せずメジャー版が上がることがある
  4. npm auditは件数より中身を見る。 ビルドのときだけ使うツールの中の脆弱性は、実害がほぼないこともある。アドバイザリが取り下げられることもある
  5. ライブラリのメジャー版を上げたら、見た目も確かめる。 swiper 11以降のaddIconsのように、ビルドが通っても表示が変わることがある
  6. Dependabotで「放っておいてたまる」を防ぐ。 ただしNode本体は対象外

対応のチェックリスト

  • node -vで、ローカルのNodeが修正版か確かめる
  • .nvmrcとpackage.jsonのenginesで、Nodeの版を明記する
  • 本番環境(Vercelなど)のNodeの版の設定を確かめ、再デプロイする
  • npm ciで依存パッケージを入れ直し、ビルドと表示を確かめる
  • npm auditを実行して、criticalとhighの中身を確かめる
  • "latest"指定をやめて、版を決める
  • 更新したあと、ブラウザで見た目と動きを確かめる
  • Dependabot alertsとsecurity updatesをオンにして、dependabot.ymlを置く

放っておいているNext.jsのプロジェクトがある人は、Nodeのセキュリティリリースをきっかけに、一度npm auditを実行してみることをおすすめします。

参考