CVE-2026-44727: jupyter-server: stored XSS yields kernel RCE

GHSA-fcw5-x6j4-ccmp CRITICAL
Published June 18, 2026
CISO Take

A stored XSS in jupyter-server's nbconvert endpoint allows any attacker who can place a malicious notebook in a shared location to achieve full kernel-level code execution on the victim's Jupyter instance. Because rendered HTML runs under the Jupyter origin with no CSP sandbox directive and HTMLExporter applies zero sanitization, a single page visit to /nbconvert/html/<path> exfiltrates the session token and grants the attacker unrestricted /api/* access — including spawning kernels and running arbitrary Python. With 1,874 downstream dependents and jupyter-server embedded in virtually every modern ML development environment (JupyterHub, SageMaker Studio, hosted notebook platforms), the blast radius extends to cloud credentials, model weights, and training data on any affected server. Patch to jupyter-server 2.20.0 immediately; for containerized builds, apply the two-line config override to NbconvertFileHandler and NbconvertPostHandler documented in the advisory.

Sources: GitHub Advisory ATLAS OpenSSF

What is the risk?

HIGH to CRITICAL. The vulnerability class — stored XSS with same-origin API authority — is well-understood and trivially weaponized; no novel exploit research is required. Exploitation requires only that an authenticated user opens a nbconvert HTML view of a malicious notebook, which is a routine collaborative workflow. In ML/AI environments this translates to kernel RCE on servers that typically hold cloud provider credentials in environment variables, API keys for LLM providers, GPU infrastructure access, and sensitive training datasets. The 20 prior CVEs in this package and an OpenSSF Scorecard of 5.8/10 signal a chronically underinvested security posture in a widely deployed dependency.

How does the attack unfold?

Notebook Poisoning
Attacker authors or modifies a notebook embedding a malicious HTML/JS payload in a display_data output cell and pushes it to a shared repository or artifact store accessible to the target.
AML.T0011
XSS Trigger
Authenticated victim navigates to /nbconvert/html/<path>; jupyter-server renders the notebook HTML under the Jupyter origin without a CSP sandbox, executing the attacker's script.
AML.T0049
Token Exfiltration
The XSS payload reads the Jupyter session cookie and POSTs it to an attacker-controlled server, granting full same-origin /api/* access.
AML.T0025
Kernel RCE
Using the stolen token, attacker authenticates to /api/kernels, spawns a Python kernel, and executes arbitrary commands — harvesting cloud credentials, LLM API keys, and model artifacts from the host.
AML.T0050

What systems are affected?

Package Ecosystem Vulnerable Range Patched
Jupyter pip No patch
13.2K OpenSSF 5.8 1.9K dependents Pushed 5d ago 75% patched ~11d to patch Full package profile →
Jupyter pip <= 2.19.0 2.20.0
13.2K OpenSSF 5.8 1.9K dependents Pushed 5d ago 75% patched ~11d to patch Full package profile →
Jupyter Notebook pip No patch
13.2K OpenSSF 5.8 3.0K dependents Pushed 5d ago 53% patched ~454d to patch Full package profile →

How severe is it?

CVSS 3.1
N/A
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
Trivial

What should I do?

6 steps
  1. Upgrade jupyter-server to >= 2.20.0 immediately — this is the definitive fix.

  2. For containerized or read-only deployments where patching is impractical, apply the CSP sandbox workaround in jupyter_server_config.py: monkey-patch content_security_policy on both NbconvertFileHandler and NbconvertPostHandler to append '; sandbox allow-scripts' (exact code in the advisory).

  3. Restrict the /nbconvert/ endpoint at the reverse proxy layer for public-facing instances to authenticated internal networks only.

  4. Audit shared notebook repositories for suspicious display_data HTML payloads — grep for <script, onerror=, javascript:, and data: URI patterns in cell outputs.

  5. Rotate Jupyter tokens and any cloud/LLM API credentials accessible from affected server environments.

  6. Enforce per-user server isolation in JupyterHub to limit lateral blast radius.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Art. 15 - Accuracy, robustness and cybersecurity
ISO 42001
A.6.1.3 - Information security in AI system development lifecycle
NIST AI RMF
MANAGE 2.2 - Mechanisms to sustain treatment of identified AI risks are in place
OWASP LLM Top 10
LLM05:2025 - Improper Output Handling

Frequently Asked Questions

What is CVE-2026-44727?

A stored XSS in jupyter-server's nbconvert endpoint allows any attacker who can place a malicious notebook in a shared location to achieve full kernel-level code execution on the victim's Jupyter instance. Because rendered HTML runs under the Jupyter origin with no CSP sandbox directive and HTMLExporter applies zero sanitization, a single page visit to /nbconvert/html/<path> exfiltrates the session token and grants the attacker unrestricted /api/* access — including spawning kernels and running arbitrary Python. With 1,874 downstream dependents and jupyter-server embedded in virtually every modern ML development environment (JupyterHub, SageMaker Studio, hosted notebook platforms), the blast radius extends to cloud credentials, model weights, and training data on any affected server. Patch to jupyter-server 2.20.0 immediately; for containerized builds, apply the two-line config override to NbconvertFileHandler and NbconvertPostHandler documented in the advisory.

Is CVE-2026-44727 actively exploited?

No confirmed active exploitation of CVE-2026-44727 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-44727?

1. Upgrade jupyter-server to >= 2.20.0 immediately — this is the definitive fix. 2. For containerized or read-only deployments where patching is impractical, apply the CSP sandbox workaround in jupyter_server_config.py: monkey-patch content_security_policy on both NbconvertFileHandler and NbconvertPostHandler to append '; sandbox allow-scripts' (exact code in the advisory). 3. Restrict the /nbconvert/ endpoint at the reverse proxy layer for public-facing instances to authenticated internal networks only. 4. Audit shared notebook repositories for suspicious display_data HTML payloads — grep for <script, onerror=, javascript:, and data: URI patterns in cell outputs. 5. Rotate Jupyter tokens and any cloud/LLM API credentials accessible from affected server environments. 6. Enforce per-user server isolation in JupyterHub to limit lateral blast radius.

What systems are affected by CVE-2026-44727?

This vulnerability affects the following AI/ML architecture patterns: ML training pipelines, AI development environments, MLOps platforms, Multi-user JupyterHub deployments, Data science workspaces.

What is the CVSS score for CVE-2026-44727?

No CVSS score has been assigned yet.

What is the AI security impact?

Affected AI Architectures

ML training pipelinesAI development environmentsMLOps platformsMulti-user JupyterHub deploymentsData science workspaces

MITRE ATLAS Techniques

AML.T0011.003 Malicious Link
AML.T0025 Exfiltration via Cyber Means
AML.T0049 Exploit Public-Facing Application
AML.T0050 Command and Scripting Interpreter
AML.T0055 Unsecured Credentials
AML.T0106 Exploitation for Credential Access

Compliance Controls Affected

EU AI Act: Art. 15
ISO 42001: A.6.1.3
NIST AI RMF: MANAGE 2.2
OWASP LLM Top 10: LLM05:2025

What are the technical details?

Original Advisory

The nbconvert HTTP handlers in jupyter_server render user-authored notebook HTML under the Jupyter origin without a sandbox directive in their `Content-Security-Policy`. Combined with `nbconvert.HTMLExporter`'s default non-sanitizing behavior, a notebook carrying an HTML payload in a display_data output triggers stored XSS with cookie access, full /api/* authority, and kernel RCE. ### Impact An authenticated victim who navigates to `/nbconvert/html/<path>` containing attacker-authored output can have their token exfiltrated to another domain because it is executed in the Jupyter origin. ### Patches Fixed in v2.20.0, commit [6cbee8d](https://github.com/jupyter-server/jupyter_server/commit/6cbee8d65e71abac851c4492fea987ad080580bd) ### Workarounds For deployments where editing the installed jupyter_server is impractical (containerized builds, read-only images), adding this to jupyter_server_config.py has the same effect as the patch above without touching source files: ``` import jupyter_server.nbconvert.handlers as _nb def _csp(self): return super(type(self), self).content_security_policy + "; sandbox allow-scripts" _nb.NbconvertFileHandler.content_security_policy = property(_csp) _nb.NbconvertPostHandler.content_security_policy = property(_csp) ```

Exploitation Scenario

An attacker with write access to a shared notebook repository — GitHub, an internal artifact store, or an S3 bucket used for ML experiment sharing — uploads a notebook with a crafted display_data output containing JavaScript that on render POSTs document.cookie and a fetch of /api/kernels to an attacker-controlled C2 server. A data scientist or ML engineer running jupyter-server <= 2.19.0 previews the notebook via /nbconvert/html/<path> as part of a code review or experiment handoff. The XSS payload fires in the Jupyter origin, the attacker receives the session token in real time, immediately authenticates to /api/kernels/execute, and runs arbitrary shell commands — extracting AWS_ACCESS_KEY_ID and OPENAI_API_KEY from the process environment and pivoting to the broader ML infrastructure.

Weaknesses (CWE)

CWE-1021 — Improper Restriction of Rendered UI Layers or Frames: The web application does not restrict or incorrectly restricts frame objects or UI layers that belong to another application or domain.

  • [Implementation] The use of X-Frame-Options allows developers of web content to restrict the usage of their application within the form of overlays, frames, or iFrames. The developer can indicate from which domains can frame the content. The concept of X-Frame-Options is well documented, but implementation of this protection mechanism is in development to cover gaps. There is a need for allowing frames from multiple domains.
  • [Implementation] A developer can use a "frame-breaker" script in each page that should not be framed. This is very helpful for legacy browsers that do not support X-Frame-Options security feature previously mentioned. It is also important to note that this tactic has been circumvented or bypassed. Improper usage of frames can persist in the web application through nested frames. The "frame-breaking" script does not intuitively account for multiple nested frames that can be presented to the user.

Source: MITRE CWE corpus.

Timeline

Published
June 18, 2026
Last Modified
June 18, 2026
First Seen
June 18, 2026

Related Vulnerabilities