## https://sploitus.com/exploit?id=6DC85E25-562C-5013-9637-8ECC82BB80F9
# CVE-2026-40864 โ JupyterHub XSRF bypass via cross-origin form POST (`Sec-Fetch-Mode: no-cors`)
**Severity**: Moderate
**CWE**: CWE-352 โ Cross-Site Request Forgery (XSRF)
**Affected**: `jupyterhub` 4.1.0 โค version ` posting to a different origin โ
precisely the classic CSRF vector the token is supposed to stop. So any state-changing endpoint that
accepts a simple form body, and relies solely on this XSRF gate, is forgeable cross-origin.
Mapping that to real endpoints: `/hub/spawn` (start the victim's server) and `/hub/accept-share`
(make the victim accept a share of the attacker's server) are both form POSTs behind this gate.
## Impact
- **`/hub/spawn`** โ an attacker page can spawn the victim's single-user server without consent
(resource consumption / unexpected state; the attacker does not gain access to that server).
- **`/hub/accept-share`** โ when the attacker is a JupyterHub user permitted to share their own
server, they can force a victim to *accept a share*, giving the victim access to the **attacker's**
server (a setup step for further social-engineering / data-drop scenarios).
## Root cause
Using `Sec-Fetch-Mode` as an origin oracle is unsound: `no-cors` does not imply same-origin. The fix
in 5.4.5 stops trusting `no-cors` as same-origin. Operators who cannot upgrade immediately can drop
requests carrying `Sec-Fetch-Mode: no-cors` at the reverse proxy.
## Proof of Concept
`poc/csrf_spawn.html` โ host it on any attacker origin and have a logged-in JupyterHub user open it.
The auto-submitting form issues a cross-origin POST to `/hub/spawn` (browser sends
`Sec-Fetch-Mode: no-cors`); vulnerable builds accept it with no valid `_xsrf` token and spawn the
victim's server. Point `action` at `/hub/accept-share` for the share-acceptance variant.
```
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
```
## Disclosure timeline
- Reported privately via GitHub Security Advisory
- Fixed in JupyterHub **5.4.5**
- Advisory **GHSA-m68r-v472-jgq9** published; CVE-2026-40864 assigned
---
*Disclosed responsibly. PoC published after the fix shipped.*