Node.js 2026年10月のセキュリティリリース:自分の環境が対象か調べて更新する手順

未分類

2026-10-21、Node.js が 26.x・24.x・22.x の3系統にセキュリティリリースを出した。深刻度 High が4件含まれる。手元やサーバーで Node.js を動かしているなら、使っている系統の修正版へ上げる。 回避策は公表されておらず、更新が唯一の対処になる。

系統修正版最高深刻度
26.xv26.12.1High
24.xv24.22.1High
22.xv22.23.4High

サポートが終わった系統(20.x 以前など)は、公式の方針として「常に影響を受けるもの」とされる。修正版は出ないので、サポート中の系統へ移る。

何が直ったか

公式の告知に載っている一覧は次のとおり(2026-10-22 時点)。

CVE深刻度内容対象系統
CVE-2026-111497HighBrotli 伸長処理の範囲外書き込み(リモートコード実行につながりうる)26 / 24 / 22
CVE-2026-106069Highホスト名が IP アドレスに緩く解釈されると TLS 証明書のホスト名検証をすり抜ける26 / 24 / 22
CVE-2026-105483High全角数字で書いた IP アドレスで TLS 証明書のホスト名検証をすり抜ける26 / 24
CVE-2026-105482Highdns.resolve が NUL 文字を含む名前を途中で切る26 / 24 / 22
CVE-2026-105481Mediumkeep-alive のソケットが、リクエスト送信前に書かれた応答を処理してしまう26 / 24 / 22
CVE-2026-106072Medium正規形でない IPv4 表記のホスト名で、DNS 名の SAN が IP 接続先を認証してしまう26 / 24 / 22
CVE-2026-106074Mediumスタートアップスナップショットや単一実行ファイル(SEA)で crypto.randomUUID() などの乱数キャッシュが保存され、毎回同じ値になる26 / 24 / 22
CVE-2026-106073LowPermission Model を fs.realpathSync で迂回できる26 / 24 / 22
CVE-2026-106070LowZIP ヘッダ検証に失敗したあと、攻撃者が制御するバイト列を返す26 のみ
CVE-2026-106071LowPermission Model のワイルドカード指定でファイルシステム権限を過剰に与える26 のみ

同梱ライブラリも更新されている。c-ares・undici・ルート証明書(eMudhra の中間 CA 侵害への対応を含む)は全系統、OpenSSL は 24.x と 22.x、SQLite は 22.x で上がった。

発動条件の詳細は、2026-10-22 時点で公開されていない。 告知とリリースノートには CVE の題名とコミットの題名しかなく、GitHub のセキュリティアドバイザリにもまだ載っていない。たとえば Brotli の件が「どの API を通ったときに起きるか」は書かれていない。ただ、Node.js 標準の fetch は Content-Encoding: br の応答を自動で展開するので、外部のサーバーへ fetch しにいくスクリプトも無関係とは言い切れない。「サーバーを公開していないから関係ない」とは判断しないほうがよい。

手元の Node が対象か調べる

調べるのは「いま node と打って動くもの」だけでは足りない。バージョン管理ツールの中に複数の版が入っていたり、定期ジョブが特定の版を直接指していたりするからだ。次の順に見る。

1. いま動く node と、入っている全部の版

which -a node     # PATH 上の node をすべて
node -v

# mise を使っている場合
mise ls node

# Homebrew を使っている場合(macOS)。node と node@22 などの版付き formula をすべて出す
brew list --versions | grep '^node'

# nvm を使っている場合
nvm ls

v22.23.4 / v24.22.1 / v26.12.1 より古いものが1つでもあれば対象。

2. プロジェクトごとの版の固定

.tool-versions・mise.toml・.nvmrc・.node-version で版を固定しているリポジトリは、グローバルの既定を上げても、そのディレクトリでは古い版が動き続ける。

# リポジトリ群をまとめて調べる例
for d in ~/git_repo/*/; do
  for f in .tool-versions mise.toml .nvmrc .node-version; do
    [ -f "$d$f" ] && echo "$(basename "$d") $f: $(tr -d '\r\n' < "$d$f")"
  done
done

3. 定期ジョブが node をどう呼んでいるか

ここが一番見落としやすい。タスクスケジューラ(Windows)、launchd(macOS)、cron のジョブが、バージョン付きの絶対パスで node を直接呼んでいることがある。

# 例: バッチファイルの中身
"C:\Users\<user>\AppData\Local\mise\installs\node\22.22.2\node.exe" update.mjs

このジョブは、mise で新しい版を入れても 22.22.2 のまま動き続ける。さらに後で古い版を消すと、ジョブが黙って起動しなくなる。

# macOS: launchd のジョブで node を使っているもの
grep -l node ~/Library/LaunchAgents/*.plist
crontab -l | grep node
# Windows: 有効なタスクの実行コマンドを一覧
Get-ScheduledTask | Where-Object State -ne 'Disabled' |
  ForEach-Object { $_.TaskName + ' => ' + (($_.Actions | ForEach-Object { $_.Execute + ' ' + $_.Arguments }) -join ' | ') }

.cmd や .sh を呼んでいるジョブは、そのファイルの中身まで開いて node のパスを確かめる。

対象外のもの

同じ「Node.js っぽいもの」でも、今回の修正と関係しないものがある。

  • Cloudflare Workers: nodejs_compat フラグは Node.js の API を互換実装で提供するもので、Node.js 本体は動いていない。実行環境(workerd)は Cloudflare が更新する
  • 静的サイト(SSG)の配信: ビルドに Node.js を使っても、本番で配信しているのは HTML と JS のファイルだけ。本番側で Node.js は動かない。ビルドする手元の Node は更新対象
  • 単体の実行ファイルとして配られている CLI: たとえば Claude Code のネイティブ版は単体の実行ファイルで、システムに入っている Node.js を使わない。こうしたツールの更新は配布元に任せる。逆に、npx で起動する MCP サーバーなどはシステムの Node.js で動くので対象
  • 他社製品に同梱された Node.js: GPU ドライバ付属のツールなど、製品の中に Node.js を抱えているものがある。自分では差し替えられないので、その製品のアップデートを当てる

更新する

順番が大事。 新しい版を入れる → 古い版を指している場所を書き換える → 動作を確かめる → 最後に古い版を消す。古い版を先に消すと、絶対パスで呼んでいたジョブが止まる。

mise

まず mise ls node で、グローバルの既定がどの系統かを見る(設定ファイルの欄に ~/.config/mise/config.toml が出ている行が既定)。mise use -g には、いま既定にしている系統の修正版を渡す。 24 系を既定にしている環境で [email protected] を渡すと、既定が 22 系に下がる。

# 既定が 22 系なら
mise install [email protected]
mise use -g [email protected]

# 既定が 24 系なら
mise install [email protected]
mise use -g [email protected]

# 既定ではないが別の系統も入っているなら、install だけする
mise install [email protected]

.tool-versions で nodejs 24.12.0 のように固定しているリポジトリは、そのファイルを 24.22.1 に書き換える。

Homebrew(macOS)

brew update
brew list --versions | grep '^node'   # 入っている formula を確認
brew info node        # stable が 26.12.1 になっているか確認
brew upgrade node
node -v

node@22・node@24 のような版付きの formula を入れている場合、brew upgrade node はそれを更新しない。入っているものごとに brew upgrade node@22 のように名前を指定する。

Homebrew の formula は公式リリースから数時間〜数日遅れて更新されることがある。 brew info node がまだ古い版を示すなら、formula が追いつくのを待つか、nodejs.org のインストーラや mise を使う。

絶対パスで呼んでいるジョブ

バッチファイルや plist の中の .../node/22.22.2/node.exe を新しい版のパスへ書き換え、一度手で実行してログを確かめる。

mise の shims のパスを呼ぶ形に変えれば、次回から書き換えずに済む。ただしその場合、開発の都合でグローバルの既定を戻したり上げたりすると、ジョブも確認なしに同じ版へ切り替わる。 定期ジョブは版番号を書いたまま、起動時に node -v をログへ残しておくほうが安全だ。書き換え漏れは翌日のログで分かる。

CI(GitHub Actions)

actions/setup-node に node-version: '22' のようにメジャー番号だけを書いていても、GitHub のホスト型ランナーには版がプリインストールされており、既定ではそれが使われる。 ランナーイメージの更新を待たずに修正版を使いたいなら check-latest: true を足す。

- uses: actions/setup-node@v4
  with:
    node-version: '22'
    check-latest: true

古い版を消す

ジョブとリポジトリの固定を全部書き換え、動作を確かめてから消す。

mise uninstall [email protected]

mise prune でまとめて消す方法もあるが、mise が見ているのは自分の設定ファイルだけだ。バッチファイルや plist が絶対パスで指している版は「使われていない」と判断されて消える。 書き換えが済む前には使わない。

どこから手を付けるか

全部を一度に直せないときは、次の順に優先する。

  1. インターネットからの接続を受けるサーバー(HTTP サーバー、Webhook の受け口)
  2. 外部のサーバーへ定期的にアクセスするジョブ(スクレイピング、API の定期取得)。人が見ていない時間に動き、TLS や応答の展開処理を通る
  3. ふだんの開発で使う node と、npx で起動するツール
  4. CI のランナー

参考

#Node.js#セキュリティ#mise#Homebrew#脆弱性対応