nginxの2026年5月第2波が来た njsのCVE-2026-8711とrewrite追加分のCVE-2026-9256をRift続報として整理
目次
TL;DR
CVE-2026-8711 (njs) NGINX JavaScript 0.9.4〜0.9.8、js_fetch_proxy がクライアント制御変数($http_* / $arg_* / $cookie_* など)を含み、ngx.fetch() を呼ぶlocationと組み合わさる構成。njs 0.9.9で修正
CVE-2026-9256 (rewrite) nginx 0.1.17〜1.31.0、ngx_http_rewrite_module で overlapping captures(例: ^/((.*))$)を持つrewriteと、変数を含まない複数キャプチャ参照の置換文字列。nginx 1.30.2 / 1.31.1で修正
共通 どちらも未認証で発火、ワーカープロセスのヒープバッファオーバーフロー(CWE-122)、ASLR次第でRCE。CVSS v4.0 9.2 CRITICAL
5月13日のCVE-2026-42945(NGINX Rift)で済んだ話かと思ったら、その後の2週間でnginx側からさらに2件出た。
5月19日にNGINX JavaScript(njs)モジュールのCVE-2026-8711、5月22日にrewriteモジュールの別のヒープオーバーフローCVE-2026-9256。
両方ともCVSS v4.0で9.2 CRITICAL、両方とも未認証で踏める。
Riftの4件チェーンとは別の独立CVEなので、Rift修正版(1.30.1 / 1.31.0)に上げた環境でも今回のCVE-2026-8711とCVE-2026-9256は別途パッチが要る。
それぞれ発火条件が違うので順に確認する。
CVE-2026-8711 njs の js_fetch_proxy がクライアント変数を解釈するとき壊れる
NGINX JavaScript(njs)は ngx_http_js_module を経由してnginxの設定からJavaScriptを呼ぶ拡張だ。
そのなかの js_fetch_proxy ディレクティブで、クライアント制御変数を含むURLを設定し、かつnjs側の ngx.fetch() を呼ぶlocationと組み合わせると、ワーカープロセスのヒープバッファオーバーフローを起こす。
NVDの記述から引くと、対象になるのは「js_fetch_proxy が少なくとも1つのクライアント制御NGINX変数で設定されている」場合だ。
具体的には $http_*(リクエストヘッダ)、$arg_*(クエリ文字列)、$cookie_*(クッキー)など、攻撃者がHTTPリクエストで自由に書ける変数群。
# 形だけを示す例。本番でこのまま使うものではない。
location /proxy {
js_fetch_proxy http://upstream.example.com$arg_target;
js_content fetchHandler;
}
$arg_target のようにクライアント側から値を入れられる変数を js_fetch_proxy の引数に置き、その先で ngx.fetch() を呼ぶ作りが該当する。
nginxを単に「動的アップストリームの分岐」として使うために js_fetch_proxy を採用しているケースが現実的に踏みやすい。
CVSSはv4.0で9.2 CRITICAL、v3.1で8.1 HIGH(CWE-122)。
基本影響はワーカープロセスのクラッシュ(DoS)で、ASLRが無効、または攻撃者がASLRをバイパスできる場合にワーカー権限での任意コード実行に届く。
これはRiftと同じ位置づけだ。
修正版はnjs 0.9.9。
影響範囲はNGINX OSSとNGINX Plusの データプレーン のみで、F5のBIG-IP / BIG-IQ / コントロールプレーンは対象外(F5アドバイザリK000161307)。
Plus側はRバージョンごとに別のホットフィックスが必要なので、F5側のアドバイザリで自分の使っているRバージョンを確認する。
njsを使っていない環境は基本的に無関係だが、nginxパッケージにnjsが同梱されているディストリビューションでは、設定で load_module を呼んでいなくてもバイナリは入っているので、nginx -V で --with-http_js_module が含まれているか、load_module modules/ngx_http_js_module.so; 行が設定にあるかを確認する。
読み込んでいなければ攻撃経路はない。
CVE-2026-9256 rewriteの「overlapping captures」で確保バッファが足りなくなる
5月22日リリースのnginx 1.30.2 stable / 1.31.1 mainlineで、ngx_http_rewrite_module の別のヒープバッファオーバーフローが修正された。
Riftの修正で済まなかった残りが見つかった形だ。
1.31.1のchangelog原文を引く:
*) Security: a heap memory buffer overflow might occur in a worker process when using a configuration with overlapping captures in ngx_http_rewrite_module, potentially resulting in arbitrary code execution (CVE-2026-9256). Thanks to Mufeed VH of Winfunc Research.
キーワードは overlapping captures(重複するキャプチャ)だ。
PCREの正規表現で ^/((.*))$ のように外側と内側の括弧が両方キャプチャになっているパターンと、置換文字列が $1$2 のように複数キャプチャを参照していて、しかも変数を含まない場合、確保したバッファがエスケープ後の書き込みサイズより小さくなる。
# 形だけを示す例。発火条件のパターンを示すだけ。
rewrite ^/((.*))$ /target/$1$2 last;
外側 (.*) が $1、内側 (.*) が $2 という重複キャプチャになっていて、置換文字列がその両方を参照する。
こういう書き方は手書きでは滅多に出ないが、.htaccess から自動変換したnginx設定、CMSの管理画面で生成された設定、Ingress ControllerのアノテーションがConfigMapに展開された後の nginx.conf には残っていることがある。
評価のズレに注意したい。
nginx.org側の深刻度表記は medium だが、F5/NVDのCVSS v3.1は 8.1 HIGH、v4.0は 9.2 CRITICAL。
このズレはRiftの記事で書いたものと同じ構造で、nginx側は「設定条件つき・ASLR次第」を反映し、CVSS側は「未認証・ネットワーク到達・C/I/A高影響」を強く評価している。
影響バージョンは 0.1.17から1.31.0まで。
つまりRift修正版の1.31.0でも該当するので、1.31.1 / 1.30.2へ上げる。
nginx Plus側はR37で37.0.1.1、R36でR36 P5、R32でR32 P7(二次情報経由、F5 K000161377で最終確認推奨)。
PoCはNebula Securityが5月20日にティーザーを投稿したが、本記事執筆時点(2026-05-26)で完全な公開PoCは確認できていない。
ITW(in the wild)の悪用も、Riftと混同された二次情報はあるが、9256単体での確認はできていない。
ただしRiftがVulnCheckのハニーポットで実際の悪用試行を観測した経緯を踏まえると、PoCが完全公開された時点で同じパターンの無差別スキャンが始まる。
確認の順番
Riftの記事と同じく、対象設定の有無 → 公開到達性 → ASLR有効性、の順で見るのが現実的だ。
nginx本体側の確認は nginx -T で展開後の設定をまとめて出し、grepで以下の3つを見る。
# 1. njs js_fetch_proxy にクライアント変数が混じっているか
nginx -T 2>/dev/null | grep -E 'js_fetch_proxy.*\$(http_|arg_|cookie_)'
# 2. njs モジュール自体が読み込まれているか
nginx -T 2>/dev/null | grep -E 'load_module.*ngx_http_js_module'
# 3. rewrite の重複キャプチャ + 複数キャプチャ参照
nginx -T 2>/dev/null | grep -E 'rewrite.*\(\(.*\)\).*\$[0-9]+\$[0-9]+'
3つ目のgrepは形だけのフィルタなので、引っかかったら設定を目で見て「重複キャプチャ + 変数なし置換」になっているか確認する。
include経由でロードされたsnippetは nginx -t だけだと見落とすので、必ず nginx -T(大文字T、設定全体ダンプ)を使う。
WAF製品やIngress Controllerを介してnginx設定が生成される環境では、上位の設定ファイル(CRD、Helmのvalues、テンプレート)だけ見ても判断できない。
Pod内で実際に動いている nginx.conf をダンプして確認する。
なぜ立て続けに同じ場所から脆弱性が出るのか
Riftが5月13日、9256が5月22日、間が9日。
公開クレジットはRiftがLeo Lin / DepthFirst、9256がMufeed VH / Winfunc Researchで別研究者だが、両方とも ngx_http_rewrite_module 内の PCREキャプチャを置換文字列に展開する処理 だ。
Rift発表後にこの処理周辺を別の角度から監査した研究者が、別パターンで同じクラスのバグを見つけた、と読むのが自然だ。
nginxは18年間動いてきたコードで、PCREキャプチャの展開はもともとエスケープ前後でサイズが食い違いやすい場所だった。
Riftで一度注目が集まったので、これからしばらく ngx_http_rewrite_module の周辺で監査が続く。
njsの方は別モジュールだが、こちらも同時期にF5から出てきていて、5月のnginx一連の発表のなかでまとめて報じられた経緯がある。
ただし技術的にはRiftチェーンには入らない独立CVEなので、F5アドバイザリK000161019(Rift系)とK000161307(njs)は別に追う。
正直、.htaccess ジェネレーターを自分で作って公開しておきながら、こういう「rewriteの置換が長いと壊れる」系の脆弱性が出るたびに、自分のジェネレーター出力が踏まないか確認している。
今のところ重複キャプチャは吐かない作りなのでセーフだが、AIにrewriteを書かせてそのまま使う運用は、しばらくは生成後の設定を nginx -T で読み返したほうがいい。