
Proof-of-concept for CVE-2026-40864: JupyterHub XSRF bypass via cross-origin form POST exploiting Sec-Fetch-Mode: no-cors. Includes PoC HTML, root cause analysis, and disclosure timeline.
Sec-Fetch-Mode: no-cors)Schweregrad: Mittel
CWE: CWE-352 — Cross-Site Request Forgery (XSRF)
Betroffen: jupyterhub 4.1.0 ≤ Version < 5.4.5 (behoben in 5.4.5)
Advisory: GHSA-m68r-v472-jgq9
NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-40864
Credit: Romain Deperne
Der XSRF-Schutz von JupyterHub (überarbeitet in 4.1.0) verwendete den Sec-Fetch-Mode-Request-Header, um zu entscheiden, ob eine Anfrage vom selben Ursprung stammte. Er behandelte Sec-Fetch-Mode: no-cors als gleichen Ursprung — aber no-cors ist genau das, was ein Browser für eine sendet. Infolgedessen umgingen Cross-Origin-HTML-Formular-POSTs an die Formular-Endpunkte des Hubs (, ) die XSRF-Prüfung vollständig.
/hub/spawn/hub/accept-shareDie JSON-API ist nicht betroffen (sie erfordert einen nicht-einfachen Content-Type, der einen CORS-Preflight erzwingt). Nur die HTML-Formular-Endpunkte sind auf diese Weise erreichbar.
Die XSRF-Logik geht für eine Reihe von Sec-Fetch-*-Zuständen, die Navigationen gleichen Ursprungs erfassen sollen, direkt zu „vertrauenswürdig“. Sec-Fetch-Mode: no-cors war in dieser vertrauenswürdigen Menge enthalten. Aber no-cors ist der Modus, den der Browser einem einfachen <form method=POST> zuweist, das an einen anderen Ursprung sendet — genau der klassische CSRF-Angriffsvektor, den das Token stoppen soll. Daher ist jeder zustandsändernde Endpunkt, der einen einfachen Formularkörper akzeptiert und sich ausschließlich auf diese XSRF-Prüfung verlässt, Cross-Origin fälschbar.
Übertragen auf reale Endpunkte: /hub/spawn (Starten des Servers des Opfers) und /hub/accept-share (Das Opfer veranlassen, eine Freigabe des Servers des Angreifers zu akzeptieren) sind beides Formular-POSTs hinter dieser Absicherung.
/hub/spawn — Eine Angreiferseite kann den Einzelbenutzerserver des Opfers ohne Zustimmung starten (Ressourcenverbrauch / unerwarteter Zustand; der Angreifer erhält keinen Zugriff auf diesen Server)./hub/accept-share — Wenn der Angreifer ein JupyterHub-Benutzer ist, der seinen eigenen Server freigeben darf, kann er ein Opfer zwingen, eine Freigabe zu akzeptieren, wodurch das Opfer Zugriff auf den Server des Angreifers erhält (ein vorbereitender Schritt für weitere Social-Engineering- / Data-Drop-Szenarien).Die Verwendung von Sec-Fetch-Mode als Ursprungs-Orakel ist unsicher: no-cors impliziert nicht gleichen Ursprung. Der Fix in 5.4.5 hört auf, no-cors als gleichen Ursprung zu vertrauen. Betreiber, die nicht sofort aktualisieren können, können Anfragen mit Sec-Fetch-Mode: no-cors am Reverse-Proxy ablehnen.
poc/csrf_spawn.html — Hosten Sie es auf einem beliebigen Angreifer-Ursprung und lassen Sie einen eingeloggten JupyterHub-Benutzer es öffnen. Das automatisch absendende Formular führt einen Cross-Origin-POST an /hub/spawn durch (Browser sendet Sec-Fetch-Mode: no-cors); anfällige Builds akzeptieren es ohne gültiges _xsrf-Token und starten den Server des Opfers. Richten Sie action auf /hub/accept-share für die Variante zur Freigabeannahme.
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
Verantwortungsvoll offengelegt. PoC nach Auslieferung des Fixes veröffentlicht.