
CVE-2026-40864の概念実証:Sec-Fetch-Mode: no-corsを悪用したクロスオリジンのフォームPOSTによるJupyterHubのXSRFバイパス。PoC HTML、根本原因分析、開示タイムラインを含む。
Sec-Fetch-Mode: no-cors)によるJupyterHubのXSRFバイパス深刻度: 中 (CVSS 5.4)
CWE: CWE-352 — クロスサイトリクエストフォージェリ (XSRF)
影響範囲: jupyterhub 4.1.0 ≤ バージョン < 5.4.5(5.4.5 で修正済み)
アドバイザリ: GHSA-m68r-v472-jgq9
NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-40864
クレジット: Romain Deperne
JupyterHubのXSRF保護(4.1.0で作り直された)は、リクエストが同一オリジンかどうかを判断するために
Sec-Fetch-Mode リクエストヘッダーを使用していた。この実装は Sec-Fetch-Mode: no-cors を同一オリジンとして
扱っていたが、no-cors はまさにブラウザがクロスオリジンの「シンプルな」フォーム送信に対して送信する値である。
その結果、Hubのフォームエンドポイント(/hub/spawn、/hub/accept-share)へのクロスオリジンHTMLフォームPOSTは、
XSRFチェックを完全にバイパスできた。
JSON APIは影響を受けない(シンプルでないコンテンツタイプを要求するため、CORSプリフライトが強制される)。 この方法で到達可能なのはHTMLフォームエンドポイントのみである。
XSRFロジックは、同一オリジンのナビゲーションを捉えることを意図した一連の Sec-Fetch-* 状態に対して
「信頼済み」へショートカットしていた。Sec-Fetch-Mode: no-cors はその信頼済みセットに含まれていた。しかし no-cors
は、ブラウザが別オリジンへの単純な <form method=POST> に割り当てるモードであり、まさにトークンが防ぐべき
古典的なCSRFベクターである。したがって、シンプルなフォームボディを受け付け、このXSRFゲートのみに依存する
状態変更エンドポイントは、クロスオリジンで偽造可能である。
これを実際のエンドポイントに当てはめると、/hub/spawn(被害者のサーバーを起動する)と /hub/accept-share
(被害者に攻撃者のサーバーの共有を受け入れさせる)はどちらも、このゲートの背後にあるフォームPOSTである。
/hub/spawn — 攻撃者のページが、被害者のシングルユーザーサーバーを同意なしに起動できる
(リソース消費/予期しない状態。攻撃者がそのサーバーへのアクセスを得るわけではない)。/hub/accept-share — 攻撃者が自身のサーバーを共有することを許可されたJupyterHubユーザーである場合、
被害者に共有の受け入れを強制でき、被害者に攻撃者のサーバーへのアクセスを与える
(さらなるソーシャルエンジニアリング/データドロップのシナリオへの足がかり)。Sec-Fetch-Mode をオリジンの判定材料として使うのは不健全である。no-cors は同一オリジンを意味しない。
5.4.5での修正により、no-cors を同一オリジンとして信頼することがなくなった。直ちにアップグレードできない
運用者は、リバースプロキシで Sec-Fetch-Mode: no-cors を持つリクエストを破棄できる。
poc/csrf_spawn.html — 任意の攻撃者オリジンでホストし、ログイン済みのJupyterHubユーザーに開かせる。
自動送信フォームが /hub/spawn へクロスオリジンPOSTを発行し(ブラウザは Sec-Fetch-Mode: no-cors を送信する)、
脆弱なビルドは有効な _xsrf トークンなしでこれを受け入れ、被害者のサーバーを起動する。共有受け入れの
バリアントでは、action を /hub/accept-share に向ける。
1. Edit TARGET-JUPYTERHUB in poc/csrf_spawn.html
2. Serve the file from an attacker origin (any static host)
3. Open it in a browser already authenticated to the target Hub
4. Observe the victim's server spawn with no XSRF token supplied
責任ある方法で開示。PoCは修正のリリース後に公開。