手元のMacで、いま node -v を打ったら、何と返ってくるでしょうか。
私が10月22日の夕方にこれを打ったとき、返ってきたのは v25.8.1。前の日にNode.jsが10件の脆弱性を直すセキュリティリリースを出していて、修正版は22・24・26の3系統だけ。25という数字は、そのどこにもありませんでした。
この記事は、そこから26.12.1に上げるまでの記録です。手順そのものは brew upgrade node の一行で終わる話なのですが、出てきたログを読んでいくと、Homebrewで入れたNode.jsならではの事情がいくつか見えてきました。同じようにHomebrewでNode.jsを入れている方には、たぶん他人事ではないと思います。


10月21日:PHPの次は、Node.jsだった
前の晩は、PHPの「php2shell」の修正版を待っていました。その話は別の記事に書いたので省きますが、同じ10月21日(現地時間)に、Node.jsもセキュリティリリースを出していました。予告は2日前の19日に出ていたので、PHPと同じ週に、二つの実行環境の修正が重なったことになります。
直された脆弱性は10件で、深刻度の内訳はHighが4件、Mediumが3件、Lowが3件です。CVSSの数値は公表されていません。いちばん重いのは、Node.jsが同梱しているBrotli(圧縮形式の一つ)の展開処理の不具合で、細工した圧縮データを展開させると、メモリの範囲外に書き込みが起き、リモートからコードを実行される可能性がある、とされています。
| 深刻度 | CVE | 中身 | 影響する系列 |
|---|---|---|---|
| High | CVE-2026-111497 | Brotliの展開処理で範囲外書き込み(リモートからのコード実行の可能性) | 22 / 24 / 26 |
| High | CVE-2026-106069 | 正規の書き方でないIPアドレスで、TLSのホスト名検証を回避できる | 22 / 24 / 26 |
| High | CVE-2026-105483 | 全角数字で書いたIPアドレスで、TLSのホスト名検証を回避できる | 24 / 26 |
| High | CVE-2026-105482 | dns.resolve が、名前の途中のnullバイトで名前を切り詰める | 22 / 24 / 26 |
| Medium | CVE-2026-105481 | keep-aliveの接続で、リクエスト前に書かれた応答を処理してしまう | 22 / 24 / 26 |
| Medium | CVE-2026-106072 | 正規形でないIPv4の扱いで、DNS名の証明書がIP宛ての接続を認証できてしまう | 22 / 24 / 26 |
| Medium | CVE-2026-106074 | スナップショットや単一実行ファイル(SEA)で、randomUUID() などが毎回同じ値を返す | 22 / 24 / 26 |
| Low | CVE-2026-106070 | ZIPのヘッダー検証に失敗しても、攻撃者が仕込んだバイトを返す | 26 |
| Low | CVE-2026-106071 | Permission Modelのワイルドカード検索で、ファイルのアクセスが広く許されすぎる | 26 |
| Low | CVE-2026-106073 | fs.realpathSync で、Permission Modelを回避できる | 22 / 24 / 26 |
Brotliの件は、22日の時点で実際の攻撃は報告されていません。公開された攻撃コードも、わざと守りを弱くしたテスト用のビルドでしかコード実行に至らず、通常のビルドではクラッシュとメモリの一部の読み取りにとどまった、と報じられています。攻撃の通り道は、node:zlib で直接展開する場合と、fetch() がBrotli圧縮の応答を自動で展開する場合の2つです。外から受け取った圧縮データを展開するサーバーが、いちばん急ぐべき立場になります。
PHPのときは、ほぼすべてのPHPサイトが既定の設定のまま狙われうる、という話でした。それに比べると、今回は条件がつく分、少し落ち着いて構えられる話です。ただ、修正版の出ない系列を使っている場合は、話が別になります。
同じリリースでは、ほかにc-ares、OpenSSL、SQLite、undiciといった依存ライブラリの更新と、秘密鍵の漏えいが報告されたインドの認証局eMudhraの中間証明書を拒否する変更も入っています。
10月22日 夕方:node -v が返したのは v25.8.1
私はWordPressのプラグインを作っていて、本番のサイトはPHPで動いています。Node.jsは、手元のMacでビルドツールを動かしたり、Claude Codeから呼ぶMCPサーバーを起動したりするのに使っています。外からのデータを受け取るサーバーとしてNode.jsを動かしているわけではないので、確かめるのは手元のNode.jsの版だけです。そこで node -v を打ったのが、冒頭の場面です。
Node.jsは、偶数の版が長期サポート(LTS)になり、奇数の版は半年ほどで役目を終える、という周期で出ています。25.xは奇数の版で、すでにサポートが終わっていました。サポートが終わった系列には、セキュリティの修正は出ません。今回の修正版が22・24・26の3系統だけだったのは、そういう理由です。
私のMacが25.xだった理由には、心当たりが一つしかありません。Homebrewで brew install node と入れていたからです。Homebrewの node は、その時点でいちばん新しい版を指します。入れた、あるいは最後に上げた時点では25.xがいちばん新しかったので、それが入ったのだと思います。そのあと25.xのサポートが終わっても、私が何もしなければ、Macの中ではずっと25.xのままです。最新を入れたつもりが、気づかないうちにサポートの切れた版に乗っていた、ということになります。
余談ですが、このとき最初に打ったのは、Node.jsのバージョン管理ツールの n でした。返ってきたのは command not found。夏に古い開発環境を片づけたとき、使っていなかったnもまとめて外していたのを、すっかり忘れていました。手が覚えているコマンドというのは、なかなか抜けないものです。
同じ夕方:brew upgrade node を実行する
やったことは、これだけです。一度 brew --upgrade node と打ち間違えて叱られ、打ち直しています。
実行したのは、MacBook Pro(Apple Silicon)、macOS 27 の環境です。以下のログは、実際の出力から、ダウンロードの進捗表示などを省いて抜き出したものです。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | % node -v v25.8.1 % brew upgrade node ==> Would install 7 dependencies: abseil 20260817.0 simdutf 9.3.2 libffi 3.8.0 merve 1.2.2_4 nbytes 0.1.4 openssl@4 4.0.3 highway 1.4.0 ==> Would upgrade 13 dependencies: fmt 12.1.0 -> 12.2.0 ada-url 3.4.4 -> 4.0.0_1 brotli 1.2.0 -> 1.2.1 c-ares 1.34.6 -> 1.34.9 hdrhistogram_c 0.11.9 -> 0.12.1 libnghttp2 1.69.0 -> 1.70.0 libuv 1.52.1 -> 1.53.0 llhttp 9.3.1 -> 9.4.3 ca-certificates 2026-07-16 -> 2026-10-20 simdjson 4.4.2 -> 5.0.5 readline 8.3.3 -> 8.3.6 sqlite 3.53.3 -> 3.54.1 xz 5.8.3 -> 5.8.4 ==> Would upgrade 1 requested outdated package node 25.8.1_1 -> 26.12.1 (21.3MB) ... ==> Installing node dependency: openssl@4 (4.0.3) Unlinking /opt/homebrew/Cellar/openssl@3/3.6.3... 6566 symlinks removed. ... 🍺 /opt/homebrew/Cellar/node/26.12.1: 2,077 files, 75.3MB ==> Cleanup Removing: /opt/homebrew/Cellar/node/25.8.1_1... (1,926 files, 77.8MB) ==> Caveats ==> node Single Executable Application is disabled as it doesn't work with shared libnode. ==> Upgraded 1 requested outdated package node 25.8.1_1 -> 26.12.1 |
結果だけ見れば、25.8.1から26.12.1へ、メジャーバージョンを一つまたいで上がりました。26.12.1は、今回のセキュリティリリースの修正版そのものです。これで手元のNode.js本体は、修正済みになりました。
ただ、このログには、ほかにも読むべきところがありました。以下、気になった箇所を一つずつ見ていきます。
ログを読む:Brotliは、別のパッケージとして上がっていた
依存パッケージの一覧に、brotli 1.2.0 -> 1.2.1 という行があります。最初は読み流しそうになったのですが、これは今回の本命の脆弱性に直結する行でした。
nodejs.org から落とす公式のNode.jsは、Brotliを本体の中に同梱しています。だから公式の配布物では、Node.js本体を上げれば、中のBrotliも一緒に直ります。一方、HomebrewのNode.jsは、Brotliを本体に抱えず、Homebrewの別のパッケージとして共有しています。今回の修正は、Brotliの上流の修正を取り込んだもので、同じ修正はBrotli 1.2.1にも入っている、と報じられていました。HomebrewのNode.jsの場合、Brotliの修正はNode.js本体とは別に、brotliパッケージが1.2.1に上がることで届いていた、ということです。
ほかの行も、同じ目で見ると意味がつながります。c-aresは1.34.9で、今回のNode.jsのリリースで上げられた版と同じです。ca-certificatesの日付は2026-10-20で、eMudhraの証明書の件が報告された直後の更新です。Node.jsのセキュリティリリースの中身が、Homebrewでは何本ものパッケージに分かれて届いている様子が、このログからよく見えます。
| パッケージ | 更新前 | 更新後 | 今回のリリースとの関係 |
|---|---|---|---|
| node | 25.8.1_1 | 26.12.1 | 本体。26系の修正版 |
| brotli | 1.2.0 | 1.2.1 | CVE-2026-111497の修正を含む上流の版 |
| c-ares | 1.34.6 | 1.34.9 | Node.jsのリリースで上げられた版と同じ |
| ca-certificates | 2026-07-16 | 2026-10-20 | eMudhraの件のあとの証明書一覧 |
| openssl@4 | (なし) | 4.0.3 | 新しく入った。openssl@3のリンクが外れる |
逆に言うと、HomebrewでBrotliを使っているほかのツールも、この brew upgrade で一緒に修正版のBrotliを使うようになっています。Brotliを同梱しているほかのソフトにも更新が必要になりうる、という注意が報道にありましたが、Homebrewの範囲については、Node.jsを上げたついでに片づいていたことになります。
ログを読む:openssl@3 のリンクが外れていた
もう一つ、目が止まった行があります。
Unlinking /opt/homebrew/Cellar/openssl@3/3.6.3… 6566 symlinks removed.
26.12.1のNode.jsは openssl@4 を使うため、openssl@4 が新しく入り、それまで /opt/homebrew の下に張られていた openssl@3 のリンクが外されています。
Homebrewのほかのパッケージは、自分が使うOpenSSLの版を直接参照しているので、ふつうはこれで動かなくなることはないはずです。変わるのは、ターミナルで openssl コマンドを打ったときに動く版や、自分で何かをビルドするときに拾われるヘッダーです。openssl version を打てば、いまどちらが使われているかが分かります。OpenSSLを直接使う作業をしている方は、一度確かめておくと安心です。
ログを読む:古い25.8.1は、もう残っていない
最後の Cleanup では、Removing: /opt/homebrew/Cellar/node/25.8.1_1 と、古い版がまるごと削除されています。Homebrewの既定の動きで、ディスクは空きますが、25.8.1に戻すことはもうできません。
今回のように、メジャーバージョンを一つまたいで上がった場合、手元のプロジェクトが新しい版で動かないことも、ないとは言えません。あとから戻れないのは、少し怖いところです。ビルドの多いプロジェクトを抱えている方は、上げたあとにいつものビルドを一度通しておくと安心です。
振り返ると、そもそも node という「いちばん新しい版」を指すパッケージを入れていたことが、今回の出発点でした。Homebrewには、系列を固定した node@24 のようなパッケージもあります。偶数の長期サポート版に固定しておけば、サポートの切れた奇数版に知らないうちに乗っている、ということは起こりにくくなります。そのかわり、新しい系列に移るときは自分で切り替える必要があります。どちらが合うかは、Node.jsをどれだけ使うかによると思います。
ちなみに、ログの最後の Single Executable Application is disabled という一文は、HomebrewのNode.jsでは単一実行ファイル(SEA)を作れない、という意味です。今回のMediumの1件(SEAやスナップショットで randomUUID() が同じ値を返す)は、そもそもHomebrewのNode.jsでSEAを作っている人には当てはまらない、ということになります。
そのあと:確かめたこと
| 確認すること | コマンド・方法 | 見るところ |
|---|---|---|
| Node.jsの版 | node -v | 26.12.1/24.22.1/22.23.4 以上になっているか |
| 古いNode.jsが残っていないか | which -a node | 先頭に出るのが /opt/homebrew/bin/node か。別の場所の古いNode.jsが先に見つかると、そちらが使われる |
| OpenSSLの版 | openssl version | openssl@4 に切り替わっていても困らないか |
| 動いているプロセス | Claude Code などを開き直す | npx で起動したMCPサーバーなどは、起動したときのNode.jsのまま動き続けている |
最後の行は、見落としやすいと思います。Node.jsを上げても、すでに動いているプロセスは古い版のままです。Claude CodeからnpxでMCPサーバーを起動している場合、セッションを開き直すまでは、更新前のNode.jsで動いています。
本番のサイトはPHP、手元の開発はNode.js。同じ週に両方の脆弱性が出て、サーバーのほうはホスティング会社が一晩で直してくれましたが、手元のMacは、自分で node -v を打たなければ誰も教えてくれませんでした。
もし、まだ打っていなければ、いまターミナルを開いて node -v を打ってみてください。返ってきた数字が奇数だったら、それが今日やることです。
参考にした情報
- Node.js — Wednesday, October 21, 2026 Security Releases(公式)
- Node.js Brotli Decoder Bug Could Allow Remote Code Execution in All Supported Versions(The Hacker News)
- Node.js Patches Brotli RCE Flaw, 9 Other Vulnerabilities(Cyber Kendra)
- Node.js security advisory: Brotli decoder RCE(Vercel)
- 「Node.js」のセキュリティアップデート – 10月21日以降に公開予定(Security NEXT)
Rapls Works のその他の記事
- PHP脆弱性「php2shell」(CVE-2026-109618/109619)、パッチ公開前から適用完了まで、XserverのWordPressサイトで確かめたこと ── 同じ週のPHPの件。こちらはサーバー側の話です。



コメント