Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessAuthenticate with extension API access
-
DeliveryCall PyPI extension uninstall endpoint
-
ExploitInject pip option-like name (-r/--requirement/--log)
-
Executionpip reads local file or fetches internal URL
-
ImpactReflected parse error leaks first line/response
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A05:2025 - Injection
ASVS 5.0
V1 - Encoding and Sanitization Argument sanitization
|
| Exploitation Conditions | Exploitation requires ALL of: (1) the PyPI Extension Manager is enabled; (2) the attacker is an authenticated account that can call the extension API (PR:L); and (3) kernels and terminals are disabled or delegated to remote hosts - because otherwise the same user could already read files and make outbound requests directly, nullifying any escalation. The concrete injection vectors are pip option-like uninstall names: a requirements option (-r / --requirement=) to make the server read a local file or fetch an internal URL with content reflected via parse errors, or a --log option to create/corrupt a chosen path with pip-generated log text. Limiting factors: authentication is mandatory (not remote-unauthenticated), no arbitrary file content or arbitrary disclosed line can be chosen, and there is no code execution or availability impact beyond ordinary package removal. |
| Impact | This is a genuine but moderate-severity issue best characterized as argument (parameter) injection (CWE-88), not remote code execution despite the 'RCE' tag. The vendor CVSS3.1 vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N (5.4) is consistent with the description: an authenticated (PR:L) user with extension-API access injects pip option-like arguments into the uninstall path, yielding limited file read / internal-URL fetch (C:L) and limited path create/corrupt via pip logs (I:L), with no availability impact (A:N). No EPSS score, no CISA KEV listing, and no public exploit code are provided in the input, so exploitation status is 'no public exploit identified at time of analysis.' Critically, the vendor itself scopes the real impact narrowly: the security benefit only exists when kernels and terminals are disabled or delegated to remote hosts - otherwise an authenticated user can already read files and make outbound requests directly, making this a no-op escalation. There is no signal conflict between CVSS and description; both point to a constrained, authenticated, conditionally-exploitable flaw. Net assessment: a real defense-in-depth fix worth patching, but not an urgent widespread-exploitation priority. The 'RCE' tag overstates impact - the description explicitly states the injection 'does not add code execution or availability impact.' |
| Exploit ScenarioDerived | In a locked-down JupyterHub-style deployment where kernels and terminals are disabled but the PyPI Extension Manager is left enabled, an authenticated low-privilege user calls the extension uninstall API and supplies an option-like extension name such as '-r/tmp/secret' or '--requirement=http://169.254.169.254/latest/meta-data/'. Because uninstall names were passed to 'python -m pip uninstall' without option validation, pip reads the local file or fetches the internal URL, and reflected parse errors return the first unparsable line or response content back to the attacker; a pip log option can also create/corrupt a chosen path. No public POC is referenced, though the fix commit and its regression tests demonstrate the exact malicious inputs. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Sep 29, 2026
Argument injection in JupyterLab's PyPI Extension Manager (JupyterLab 4.0.0 through 4.5.10 and the 4.6.x branch before 4.6.4) lets an authenticated account with extension API access submit pip option-like uninstall names - such as '-r/--requirement=' or '--log' - that are forwarded to 'python -m pip uninstall' without sanitization, causing the server to read a local file or fetch an internal URL (with content partially reflected through parse errors) or to create/corrupt a chosen path with pip-generated log text. Exploitation is highly conditional: the PyPI Extension Manager must be enabled, the attacker must be an authenticated user able to call the extension API (PR:L per the CVSS vector), and kernels and terminals must be disabled or delegated to remote hosts - otherwise that same user could already read files and make outbound requests directly. Note that despite the 'RCE' tag on this record, this is parameter injection (CWE-88) with only low confidentiality and integrity impact (CVSS 5.4) and no code execution; no public exploit code has been identified at time of analysis, and there is no CISA KEV confirmation of active exploitation.
RemediationAI
Vendor-released patch: upgrade JupyterLab to 4.5.11 or 4.6.4 (or a later release on the applicable branch), which adds the is_uninstall_allowed() validation hook, returns HTTP 422 for rejected uninstall names, and inserts a '--' option terminator before the package name in the pip invocation - see the advisory https://github.com/jupyterlab/jupyterlab/security/advisories/GHSA-3325-v43h-43rv and the release notes at https://github.com/jupyterlab/jupyterlab/releases/tag/v4.5.11 and https://github.com/jupyterlab/jupyterlab/releases/tag/v4.6.4. If immediate upgrading is not possible, the most effective compensating control is to remove the exposure entirely by disabling the PyPI Extension Manager (configure a read-only or non-PyPI extension manager, or remove the extension-manager extension via page config) - the trade-off is that users lose in-browser package install/uninstall and must manage extensions from the command line. Alternatively, restrict the extension manager API route (lab/api/extensions) at the reverse proxy or Jupyter Server authorization layer so that only fully trusted administrators can POST uninstall requests; since the vector is PR:L, any authenticated user with extension API access is otherwise a potential source. Note that patching the underlying pip call to use the '--' delimiter (as upstream did) is the only mitigation that preserves functionality without validation changes, and generic network controls (egress filtering) only partially reduce the internal-URL fetch variant while doing nothing for the local-file read or pip-log write variants. As a hygiene measure, ensure the extension API is not exposed to untrusted multi-user audiences in shared JupyterHub deployments, where authenticated users commonly satisfy the PR:L prerequisite.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in pypi
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
The root cause is CWE-88 (Improper Neutralization of Argument Delimiters in a Command / 'Argument Injection'). JupyterLab's extension manager handler (jupyterlab/handlers/extension_manager_handler.py, ExtensionHandler.post) previously validated extension names for the install path - PyPIExtensionManager.is_install_allowed applied packaging.utils.canonicalize_name(name, validate=True) - but for the uninstall path it passed the caller-supplied name straight into PyPIExtensionManager.uninstall and then into a subprocess invocation of 'python -m pip uninstall <name>'. Because no validation and no '--' end-of-options delimiter were applied, a name beginning with a dash is interpreted by pip as an option rather than a package: '-r <file>' / '--requirement=<file>' makes pip read a requirements file, which on parse failure is reflected back in the HTTP error, disclosing the first unparsable line or a snippet of an internal HTTP response; '--log <path>' makes pip write its own log text to an attacker-chosen path, allowing file creation or corruption. The upstream fix introduces an is_uninstall_allowed() hook on the manager base class, implements PyPIExtensionManager.is_uninstall_allowed() using the same _is_valid_package_name() helper (rejecting names such as '-r/tmp/requirements.txt', '-rrequirements.txt', '--requirement=/tmp/requirements.txt' and '--help'), returns an HTTP 422 from ExtensionHandler.post when the check fails, and inserts a '--' separator before the package name in the pip command. Affected CPE: cpe:2.3:a:jupyterlab:jupyterlab:*:*:*:*:*:*:*:*, spanning all JupyterLab 4.x releases before the fixed versions. The impact ceiling is deliberately bounded: the requester cannot choose an arbitrary disclosed line or arbitrary file content, and package removal itself is the only availability effect - the injection adds no code execution and no availability impact beyond ordinary uninstall.
Know when Jupyterlab gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N
Authenticated extension-API user (PR:L) over the network (AV:N), low complexity (AC:L); limited file/SSRF read (C:L) and constrained path corruption (I:L), no availability impact (A:N).
Primary rating from Vendor (GitHub_M).
CVSS VectorVendor: GitHub_M
Lifecycle Timeline
2DescriptionCVE.org
JupyterLab is an extensible environment for interactive and reproducible computing, based on the Jupyter Notebook Architecture. From JupyterLab 4.0.0 until 4.5.11 and 4.6.4, the PyPI Extension Manager uninstall request reaches ExtensionHandler.post, which validates extension names for installation but passes uninstall names to PyPIExtensionManager.uninstall and python -m pip uninstall without rejecting option-like values. The security impact requires that the PyPI Extension Manager is enabled, the account can call the extension API, and kernels and terminals are disabled or delegated to remote hosts; otherwise the user can already read files and make outbound requests directly. An authenticated user with extension API access can supply a pip requirements option to make the server read a local file or fetch an internal URL, and reflected parse errors can return the first unparsable line or response content. A pip log option can also create or corrupt a chosen path with pip-generated log text, but the requester cannot select an arbitrary disclosed line or arbitrary file content, and the injection does not add code execution or availability impact beyond ordinary package removal. This issue is fixed in JupyterLab 4.5.11 and 4.6.4.
Blast Radius
ecosystem impact- 5 pypi packages depend on jupyterlab (2 direct, 3 indirect)
Ecosystem-wide dependent count for version 4.6.0.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
More in Jupyterlab
View allJupyterLab extension template is a `copier` template for JupyterLab extensions. Rated critical severity (CVSS 9.8), this
JupyterLab is a user interface for Project Jupyter which will eventually replace the classic Jupyter Notebook. Rated cri
JupyterLab is an extensible environment for interactive and reproducible computing, based on the Jupyter Notebook and Ar
jupyterlab is an extensible environment for interactive and reproducible computing, based on the Jupyter Notebook Archit
JupyterLab is an extensible environment for interactive and reproducible computing, based on the Jupyter Notebook and Ar
Plugin lock-rule enforcement bypass in JupyterLab (pip package, versions >=4.1.0,<=4.5.9 and >=4.6.0,<=4.6.1) allows aut
Stored cross-site scripting in JupyterLab's Extension Manager allows an attacker who publishes a malicious PyPI package
Improper trust attribution in JupyterLab's markdownviewer:trust and notebook:trust command-link handlers lets a Trust de
jupyterlab is an extensible environment for interactive and reproducible computing, based on the Jupyter Notebook Archit
Allowlist/blocklist enforcement in JupyterLab's PyPIExtensionManager.install() was silently bypassed due to a missing 'a
EUVD-2026-89459
GHSA-3325-v43h-43rv
NVD
CVE.org
EPSS
Vulnrichment
Exploit-DB