CVE-2026-40864 Overview
CVE-2026-40864 is a Cross-Site Request Forgery (CSRF/XSRF) vulnerability in JupyterHub, the multi-user server software for Jupyter notebooks. The flaw affects versions 4.1.0 through 5.4.4. JupyterHub's XSRF protection logic incorrectly treats requests carrying the Sec-Fetch-Mode: no-cors header as same-origin requests, bypassing XSRF checks on HTTP form endpoints. Attackers can abuse endpoints such as /hub/spawn and /hub/accept-share to trigger server spawn or coerce users into accepting share invitations to an attacker-controlled server. The JSON API is not affected. Maintainers released a fix in version 5.4.5.
Critical Impact
Attackers can bypass XSRF protections to trigger user server spawning or force users to accept access to an attacker's JupyterHub server, enabling unauthorized cross-account interactions when victims visit attacker-controlled web content.
Affected Products
- JupyterHub versions 4.1.0 through 5.4.4
- HTTP form endpoints including /hub/spawn and /hub/accept-share
- Deployments without a reverse proxy filtering Sec-Fetch-Mode: no-cors requests
Discovery Timeline
- 2026-05-22 - CVE-2026-40864 published to NVD
- 2026-05-26 - Last updated in NVD database
Technical Details for CVE-2026-40864
Vulnerability Analysis
The vulnerability is a Cross-Site Request Forgery flaw classified under [CWE-352]. JupyterHub refreshed its XSRF protection in version 4.1.0 and introduced an exemption path for browser requests deemed safe based on the Sec-Fetch-Mode header. The exemption incorrectly included the value no-cors, which browsers attach to several cross-site request types such as those initiated by HTML form submissions, image loads, and certain script-driven fetches. As a result, attacker-controlled pages can issue cross-origin requests against JupyterHub form endpoints without supplying a valid XSRF token. Exploitation requires user interaction, namely visiting a malicious page while authenticated to JupyterHub.
Root Cause
The get_xsrf_token check inside jupyterhub/_xsrf_utils.py short-circuits XSRF validation when the fetch mode equals websocket or no-cors. Treating no-cors as same-origin removes the protection it was designed to enforce, because browsers send Sec-Fetch-Mode: no-cors for many cross-site requests. The patch removes no-cors from the exemption set.
Attack Vector
An attacker hosts a page that submits a forged form (or similar no-cors request) targeting a victim's authenticated JupyterHub session. The browser attaches authentication cookies, JupyterHub skips XSRF validation, and the request executes. The attacker can force a victim to spawn a notebook server or accept a share invitation that grants the attacker access to the victim's server interface, depending on configuration. The attacker cannot directly read responses due to the same-origin policy but can drive state-changing actions.
return False
fetch_mode = handler.request.headers.get("Sec-Fetch-Mode", "unspecified")
- if fetch_mode in {"websocket", "no-cors"} or (
+ if fetch_mode == "websocket" or (
fetch_mode in {"navigate", "unspecified"}
and handler.request.method.lower() in {"get", "head", "options"}
):
Source: JupyterHub commit 9c5ec277 — the patch removes no-cors from the XSRF check bypass set, forcing those requests through standard XSRF validation.
Detection Methods for CVE-2026-40864
Indicators of Compromise
- Unexpected POST requests to /hub/spawn or /hub/accept-share with Sec-Fetch-Mode: no-cors and a cross-site Referer or Origin header.
- New JupyterHub server spawn events for users immediately following navigation to external URLs in proxy or browser logs.
- Unsolicited share-acceptance events tied to user sessions that did not interact with the share UI.
Detection Strategies
- Inspect JupyterHub access logs and reverse proxy logs for form-endpoint requests carrying Sec-Fetch-Mode: no-cors together with Sec-Fetch-Site: cross-site.
- Correlate spawn and share-acceptance audit events with browser-side referrer data to flag activity originating from non-JupyterHub origins.
- Alert on bursts of spawn requests across multiple user accounts within short time windows, which may indicate a campaign targeting authenticated sessions.
Monitoring Recommendations
- Enable verbose request logging on the reverse proxy fronting JupyterHub and forward logs to a centralized analytics platform.
- Track JupyterHub version metadata across deployments to confirm all nodes run 5.4.5 or later.
- Monitor the accept-share workflow specifically, as it is the highest-impact endpoint exposed by this vulnerability.
How to Mitigate CVE-2026-40864
Immediate Actions Required
- Upgrade JupyterHub to version 5.4.5 or later on all hub nodes.
- If immediate upgrade is not possible, configure the reverse proxy to drop requests to JupyterHub that contain Sec-Fetch-Mode: no-cors.
- Audit recent spawn and share-acceptance events for anomalous activity that may predate the fix.
Patch Information
The issue is fixed in JupyterHub 5.4.5. The fix removes no-cors from the XSRF exemption list in jupyterhub/_xsrf_utils.py, ensuring that no-cors requests are subject to full XSRF token validation. See the GitHub Security Advisory GHSA-m68r-v472-jgq9 and the upstream commit for technical detail.
Workarounds
- Drop or reject requests to JupyterHub at the reverse proxy when the Sec-Fetch-Mode header equals no-cors.
- Restrict the share permission so fewer users can issue share invitations until patching completes.
- Educate users about phishing pages that may attempt to coerce browser-driven requests to authenticated JupyterHub sessions.
# Example NGINX snippet to drop no-cors requests to JupyterHub
map $http_sec_fetch_mode $block_nocors {
default 0;
"no-cors" 1;
}
server {
listen 443 ssl;
server_name jupyterhub.example.com;
if ($block_nocors) {
return 403;
}
location / {
proxy_pass http://jupyterhub_upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


