CVE-2026-44727 Overview
CVE-2026-44727 is a stored cross-site scripting (XSS) vulnerability in Jupyter Server, the backend that powers Jupyter web applications. Prior to version 2.20, the nbconvert HTTP handlers render user-authored notebook HTML under the Jupyter origin without a sandbox directive in their Content-Security-Policy (CSP) header. Combined with nbconvert.HTMLExporter's default non-sanitizing behavior, a notebook carrying an HTML payload inside a display_data output triggers stored XSS. The attacker gains cookie access, full /api/* authority, and kernel remote code execution (RCE) on the Jupyter Server host.
Critical Impact
An authenticated user who opens or previews a malicious notebook via /nbconvert/ endpoints exposes their session to JavaScript that can issue authenticated API calls and execute arbitrary code via the kernel.
Affected Products
- Jupyter Server (jupyter_server) versions prior to 2.20
- Deployments exposing the /nbconvert/ HTTP handlers
- Multi-user Jupyter environments where notebooks can be shared or imported across accounts
Discovery Timeline
- 2026-06-22 - CVE-2026-44727 published to the National Vulnerability Database (NVD)
- 2026-06-23 - Last updated in NVD database
Technical Details for CVE-2026-44727
Vulnerability Analysis
The weakness is classified under [CWE-79] (Improper Neutralization of Input During Web Page Generation). The nbconvert handlers in Jupyter Server convert notebook documents to HTML and serve the result from the same origin as the Jupyter application. Because the response did not carry a sandbox directive in its Content-Security-Policy header, any JavaScript embedded in the rendered HTML executed with the privileges of the authenticated Jupyter session.
Notebook cells can contain display_data outputs with raw HTML payloads. The default HTMLExporter in nbconvert does not sanitize this HTML. An attacker who can deliver a malicious notebook to a victim, through shared storage, a Git repository, an email attachment, or a collaborative workspace, can land arbitrary script in the victim's browser the moment the notebook is rendered. The script then reads session cookies, calls /api/* endpoints to create or modify kernels, and submits code for execution, achieving RCE on the server.
Root Cause
Two defaults compound the issue: nbconvert's HTMLExporter does not sanitize cell outputs, and Jupyter Server's nbconvert response did not isolate that output with a sandbox CSP directive. Rendering untrusted notebook HTML under the trusted Jupyter origin allows embedded scripts to inherit the user's privileges.
Attack Vector
A remote attacker crafts a notebook containing an HTML or <script> payload in a display_data output. The victim, authenticated to a vulnerable Jupyter Server, opens the notebook through an /nbconvert/ endpoint. The browser executes the payload under the Jupyter origin, granting the attacker the victim's cookies, full REST API authority, and the ability to run arbitrary code through Jupyter kernels.
# Patch: jupyter_server/nbconvert/handlers.py
# Adds a sandbox directive to the CSP header for nbconvert responses.
auth_resource = AUTH_RESOURCE
SUPPORTED_METHODS = ("GET",)
@property
def content_security_policy(self):
# In case we're serving HTML, confine any Javascript to a unique
# origin so it can't interact with the Jupyter server.
if self.settings.get("nbconvert_csp_sandbox", True):
return super().content_security_policy + "; sandbox allow-scripts"
return super().content_security_policy
@web.authenticated
@authorized
async def get(self, format, path):
...
Source: jupyter-server commit 6cbee8d
Detection Methods for CVE-2026-44727
Indicators of Compromise
- HTTP responses from /nbconvert/ endpoints that lack a sandbox directive in the Content-Security-Policy header
- Notebooks (.ipynb) containing display_data outputs with text/html payloads that include <script>, inline event handlers (onerror, onload), or external resource fetches
- Unexpected POST requests to /api/kernels, /api/sessions, or /api/contents originating from browser sessions immediately after an /nbconvert/ GET
- Kernel execution requests issued without corresponding user-driven cell execution in the front-end UI
Detection Strategies
- Inventory Jupyter Server installations and flag any instance running a version earlier than 2.20
- Inspect web access logs for sequences where an /nbconvert/ request is followed by authenticated /api/kernels activity within the same session
- Scan notebook repositories for HTML outputs containing executable JavaScript, focusing on shared or imported notebooks
Monitoring Recommendations
- Forward Jupyter Server access logs and kernel audit events to a centralized log platform for correlation
- Alert on new outbound network connections initiated by Jupyter kernel processes that deviate from baseline behavior
- Monitor the host operating system for child processes spawned by the Jupyter kernel that match interactive shell or reconnaissance patterns
How to Mitigate CVE-2026-44727
Immediate Actions Required
- Upgrade jupyter_server to version 2.20 or later on every host running the service
- Restart the Jupyter Server process after upgrade to ensure the patched CSP handler is loaded
- Audit shared notebook stores and remove or quarantine notebooks with untrusted HTML outputs
- Restrict /nbconvert/ access to authenticated users on trusted networks where feasible
Patch Information
The fix is delivered in jupyter_server 2.20. The patch adds a new property content_security_policy to the nbconvert handlers that appends ; sandbox allow-scripts to the response CSP when the nbconvert_csp_sandbox setting is enabled, which is the new default. See the GitHub Security Advisory GHSA-fcw5-x6j4-ccmp and the upstream commit for details.
Workarounds
- Place Jupyter Server behind a reverse proxy that injects Content-Security-Policy: sandbox allow-scripts for responses from /nbconvert/ paths
- Disable or restrict the /nbconvert/ endpoints if HTML export is not required
- Treat all notebooks from external sources as untrusted and review their outputs before opening in a vulnerable instance
# Configuration example: enforce the sandbox directive after upgrading to 2.20+
# jupyter_server_config.py
c.ServerApp.nbconvert_csp_sandbox = True # default in 2.20
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

