Node.js 2026年10月のセキュリティリリース:自分の環境が対象か調べて更新する手順
2026-10-21、Node.js が 26.x・24.x・22.x の3系統にセキュリティリリースを出した。深刻度 High が4件含まれる。手元やサーバーで Node.js を動かしているなら、使っている系統の修正版へ上げる。 回避策は公表されておらず、更新が唯一の対処になる。
| 系統 | 修正版 | 最高深刻度 |
|---|---|---|
| 26.x | v26.12.1 | High |
| 24.x | v24.22.1 | High |
| 22.x | v22.23.4 | High |
サポートが終わった系統(20.x 以前など)は、公式の方針として「常に影響を受けるもの」とされる。修正版は出ないので、サポート中の系統へ移る。
何が直ったか
公式の告知に載っている一覧は次のとおり(2026-10-22 時点)。
| CVE | 深刻度 | 内容 | 対象系統 |
|---|---|---|---|
| CVE-2026-111497 | High | Brotli 伸長処理の範囲外書き込み(リモートコード実行につながりうる) | 26 / 24 / 22 |
| CVE-2026-106069 | High | ホスト名が IP アドレスに緩く解釈されると TLS 証明書のホスト名検証をすり抜ける | 26 / 24 / 22 |
| CVE-2026-105483 | High | 全角数字で書いた IP アドレスで TLS 証明書のホスト名検証をすり抜ける | 26 / 24 |
| CVE-2026-105482 | High | dns.resolve が NUL 文字を含む名前を途中で切る | 26 / 24 / 22 |
| CVE-2026-105481 | Medium | keep-alive のソケットが、リクエスト送信前に書かれた応答を処理してしまう | 26 / 24 / 22 |
| CVE-2026-106072 | Medium | 正規形でない IPv4 表記のホスト名で、DNS 名の SAN が IP 接続先を認証してしまう | 26 / 24 / 22 |
| CVE-2026-106074 | Medium | スタートアップスナップショットや単一実行ファイル(SEA)で crypto.randomUUID() などの乱数キャッシュが保存され、毎回同じ値になる | 26 / 24 / 22 |
| CVE-2026-106073 | Low | Permission Model を fs.realpathSync で迂回できる | 26 / 24 / 22 |
| CVE-2026-106070 | Low | ZIP ヘッダ検証に失敗したあと、攻撃者が制御するバイト列を返す | 26 のみ |
| CVE-2026-106071 | Low | Permission 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 が絶対パスで指している版は「使われていない」と判断されて消える。 書き換えが済む前には使わない。
どこから手を付けるか
全部を一度に直せないときは、次の順に優先する。
- インターネットからの接続を受けるサーバー(HTTP サーバー、Webhook の受け口)
- 外部のサーバーへ定期的にアクセスするジョブ(スクレイピング、API の定期取得)。人が見ていない時間に動き、TLS や応答の展開処理を通る
- ふだんの開発で使う node と、
npxで起動するツール - CI のランナー