Jul 23, 2026·5 min read·29 visits
A DOM-based Cross-Site Scripting (XSS) vulnerability in JupyterLab allows unauthenticated attackers to execute arbitrary JavaScript in a victim's session via a crafted 'overrides.json' file, potentially leading to remote command execution on the Jupyter backend.
JupyterLab versions 4.5.x and 4.6.x prior to 4.5.10 and 4.6.2 are vulnerable to a DOM-based Cross-Site Scripting (XSS) vulnerability. An attacker can craft a malicious overrides.json file that executes arbitrary JavaScript inside the victim's browser session. This can occur either automatically if the file is pre-planted on a multi-tenant filesystem, or via user interaction when importing settings.
JupyterLab is an extensible, interactive development environment for Jupyter notebooks, code, and data. In version 4.5 and above, JupyterLab introduced capabilities to share and apply settings overrides via an overrides.json file. This is commonly performed using the Import button in the Settings Editor or by reading configuration files from specific system-wide paths during application startup.
The vulnerability, tracked as GHSA-pppj-hq3g-57pj, belongs to the DOM-based Cross-Site Scripting (XSS) category. The application fails to sanitize CSS configuration options before rendering them inside the DOM. This oversight allows a malicious settings file to execute arbitrary JavaScript within the context of the user's active session.
Because settings files are often perceived as non-executable data, they represent a low-suspicion attack vector. An attacker can leverage this trust to compromise environments where users frequently import configurations. Alternatively, on shared multi-tenant filesystems, an attacker can plant the file to compromise other users sharing the same server instance.
The root cause lies in how JupyterLab processes side-by-side notebook display options. Specifically, the configuration settings sideBySideLeftMarginOverride and sideBySideRightMarginOverride are defined as unconstrained string values in the tracker schema (packages/notebook-extension/schema/tracker.json).
When JupyterLab initializes the notebook tracker via the activateNotebookHandler function in packages/notebook-extension/src/index.ts, it retrieves these margin configurations. The application then uses string template literals to construct a raw CSS stylesheet block dynamically. The unchecked string values are concatenated directly into the CSS rule-set.
To inject the style into the document, the application uses the browser's document.head.insertAdjacentHTML('beforeend', ...) API. This method interprets the input string as raw HTML markup. Because the margin strings are not sanitized, escaping or filtering characters like < or > allows an attacker to terminate the <style> context and execute arbitrary HTML elements, including <script> blocks.
A review of the fix in commit be9303f5bcd5308eaeae953c5a3c903046682c2c and f1beab4a2027af4719d6edc07d52d6cf5a39a432 reveals two primary defensive changes: strict schema validation and safe DOM manipulation.
In the schema file packages/notebook-extension/schema/tracker.json, the string type was reinforced with a strict regular expression validation pattern:
"pattern": "^-?(?:0|(?:[0-9]+|[0-9]*\\.[0-9]+)(?:px|em|rem|%|vw|vh|vmin|vmax|ch|ex|cm|mm|in|pt|pc))$"This pattern limits inputs strictly to valid CSS dimension units. It blocks special characters such as <, >, ;, or curly braces, making injection impossible via standard schema-validated paths.
Additionally, in packages/notebook-extension/src/index.ts, the dangerous DOM sink was replaced with programmatic element creation:
// Patched implementation
const style = document.createElement('style');
style.id = SIDE_BY_SIDE_STYLE_ID;
style.textContent = sideBySideMarginStyle;
document.head.appendChild(style);Using textContent rather than insertAdjacentHTML forces the browser to treat the input string as raw text rather than executable markup. Even if schema validation is bypassed or disabled, the browser will not parse or execute nested HTML tags inside the stylesheet.
The attack requires the delivery of a malicious overrides.json file. An attacker can construct this file with the payload positioned inside the sideBySideLeftMarginOverride parameter.
{
"@jupyterlab/notebook-extension:tracker": {
"sideBySideLeftMarginOverride": "10px; }</style><script>console.log(window.location.origin);</script><style>",
"sideBySideRightMarginOverride": "10px"
}
}When a victim loads this file via the Settings Editor import function, or if the file is loaded automatically from an overridden configuration path, the style generation routine executes. The browser processes the injected </style> tag, terminating the stylesheet definition immediately, and then executes the nested <script> block.
Below is the sequential logic flow of the exploit:
Once JavaScript execution is achieved inside the JupyterLab origin, the payload can access the JupyterLab API. It can then request files, execute arbitrary terminal commands through the server backend, or run malicious code in active notebook kernels.
The security impact of this vulnerability is high. Because the JavaScript runs inside the authenticated session of the JupyterLab user, the code can perform any action the user is authorized to execute. This includes reading, writing, or deleting notebooks, environment variables, and local data files.
Furthermore, because JupyterLab runs a local notebook server capable of spawning system kernels, the script can issue API commands to create or use existing kernels. This allows the attacker to execute arbitrary OS commands on the underlying server, escalating a client-side XSS to an unauthenticated remote code execution (RCE) condition on the host.
The CVSS v4.0 base score is calculated at 8.6 (High), reflecting the lack of required privileges for the social-engineering vector, and the high impact on both confidentiality and integrity of the user's environment. The vulnerability represents a severe threat in multi-tenant environments or academic compute clusters where notebooks are routinely shared among users.
The principal defense against this vulnerability is updating JupyterLab to the patched versions. Users running the 4.6.x branch must update to version 4.6.2 or later. Users running the older 3.3.0 through 4.5.x branches must update to 4.5.10 or later.
Where immediate updates are not feasible, organizations should employ several hardening measures. First, enforce strict filesystem permissions on shared Jupyter environments. Ensure that standard users cannot write to system-wide configuration directories where overrides.json might be processed automatically during another user's startup.
Second, educate users about the risks of importing untrusted configuration files. Configuration files must be audited with the same diligence as executable scripts. Lastly, implement Content Security Policies (CSP) that restrict inline script execution to reduce the impact of DOM-based XSS vulnerabilities across the platform.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:L/SC:N/SI:N/SA:L| Product | Affected Versions | Fixed Version |
|---|---|---|
jupyterlab Jupyter | >= 4.6.0, <= 4.6.1 | 4.6.2 |
jupyterlab Jupyter | >= 3.3.0, <= 4.5.9 | 4.5.10 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS v4.0 | 8.6 (High) |
| Impact | Arbitrary JavaScript Execution / RCE via Kernels |
| Exploit Status | PoC Conceptual |
| KEV Status | Not Listed |
The software does not neutralize or incorrectly neutralizes user-controlled input before it is placed in output that is used as a web page, which is then parsed and executed by a web browser.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.