GHSA-89vp-jrxv-24w8: JupyterLab: extension blocklist bypass via name mismatch
GHSA-89vp-jrxv-24w8 MEDIUMJupyterLab's extension manager blocks package installs by comparing the requested name against a blocklist using its own string-normalization logic, which is looser than PyPI's official package-name canonicalization — so a user can request a lookalike spelling like "JupyterLab.Git" instead of the blocked "jupyterlab-git" and JupyterLab will install it even though pip resolves both to the identical package. This only matters for a specific deployment shape: an operator-configured allow/blocklist, the default PyPI extension manager enabled, and kernels/terminals locked down or delegated remotely — if users already have kernel access, this bypass adds nothing since they could install the package directly anyway. There's no CVSS score, no CISA KEV listing, no public exploit code, and no scanner template for this issue, and severity is rated medium, reflecting that exploitation requires an already-authenticated user and a fairly specific hardening posture rather than an unauthenticated remote path. With 1,876 downstream dependents and 33 other CVEs on record for the jupyterlab package, this is worth tracking for any multi-tenant JupyterHub or managed-notebook environment where extension installation is meant to be restricted. Patch to JupyterLab 4.6.2 or 4.5.10 (and update any app depending on it, like Notebook 7+); if you can't patch immediately, switch to the read-only extension manager via `c.LabApp.extension_manager = 'readonly'` to disable programmatic installs entirely.
What is the risk?
Medium risk in practice. The vulnerability requires an already-authenticated user, a non-default deployment configuration (an operator-defined allow/blocklist intended to restrict installable packages), the default PyPI extension manager enabled, and kernels/terminals disabled or remoted — a fairly narrow combination. No CVSS vector, EPSS score, KEV listing, public PoC, or Nuclei template exists, and there is no evidence of active exploitation. However, where that specific hardening posture is in place (precisely the deployments that most care about restricting user actions), the bypass fully defeats the intended control with low attacker effort — it's a string-comparison logic flaw, not a complex exploit chain — making it easy to trigger once discovered.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| Jupyter | pip | >= 4.6.0, <= 4.6.1 | 4.6.2 |
Do you use Jupyter? You're affected.
How severe is it?
What should I do?
1 step-
Upgrade to JupyterLab 4.6.2 or 4.5.10 (and any dependent package, such as Notebook 7+, that bundles jupyterlab). If immediate patching isn't possible and programmatic extension installation should be disabled outright, set
c.LabApp.extension_manager = 'readonly'(or--LabApp.extension_manager=readonlyat launch) to remove the install path entirely — confirm the read-only manager is active via the GUI. Deployments without a custom allow/blocklist configured are not exposed and need no action. For detection, audit extension-install activity/logs on managed JupyterHub deployments for install requests using non-canonical package name spellings (mixed case, alternate separators) that resemble blocklisted entries.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is GHSA-89vp-jrxv-24w8?
JupyterLab's extension manager blocks package installs by comparing the requested name against a blocklist using its own string-normalization logic, which is looser than PyPI's official package-name canonicalization — so a user can request a lookalike spelling like "JupyterLab.Git" instead of the blocked "jupyterlab-git" and JupyterLab will install it even though pip resolves both to the identical package. This only matters for a specific deployment shape: an operator-configured allow/blocklist, the default PyPI extension manager enabled, and kernels/terminals locked down or delegated remotely — if users already have kernel access, this bypass adds nothing since they could install the package directly anyway. There's no CVSS score, no CISA KEV listing, no public exploit code, and no scanner template for this issue, and severity is rated medium, reflecting that exploitation requires an already-authenticated user and a fairly specific hardening posture rather than an unauthenticated remote path. With 1,876 downstream dependents and 33 other CVEs on record for the jupyterlab package, this is worth tracking for any multi-tenant JupyterHub or managed-notebook environment where extension installation is meant to be restricted. Patch to JupyterLab 4.6.2 or 4.5.10 (and update any app depending on it, like Notebook 7+); if you can't patch immediately, switch to the read-only extension manager via `c.LabApp.extension_manager = 'readonly'` to disable programmatic installs entirely.
Is GHSA-89vp-jrxv-24w8 actively exploited?
No confirmed active exploitation of GHSA-89vp-jrxv-24w8 has been reported, but organizations should still patch proactively.
How to fix GHSA-89vp-jrxv-24w8?
Upgrade to JupyterLab 4.6.2 or 4.5.10 (and any dependent package, such as Notebook 7+, that bundles jupyterlab). If immediate patching isn't possible and programmatic extension installation should be disabled outright, set `c.LabApp.extension_manager = 'readonly'` (or `--LabApp.extension_manager=readonly` at launch) to remove the install path entirely — confirm the read-only manager is active via the GUI. Deployments without a custom allow/blocklist configured are not exposed and need no action. For detection, audit extension-install activity/logs on managed JupyterHub deployments for install requests using non-canonical package name spellings (mixed case, alternate separators) that resemble blocklisted entries.
What systems are affected by GHSA-89vp-jrxv-24w8?
This vulnerability affects the following AI/ML architecture patterns: training pipelines, notebook-based ML development environments, multi-tenant JupyterHub deployments.
What is the CVSS score for GHSA-89vp-jrxv-24w8?
No CVSS score has been assigned yet.
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0010.001 AI Software Compliance Controls Affected
What are the technical details?
Original Advisory
JupyterLab's PyPI extension manager enforces `blocked_extensions_uris` by comparing the requested install name to blocklist entries with a custom string normalization that is weaker than PyPI package-name canonicalization. An authenticated user can request a PyPI-equivalent spelling such as `JupyterLab.Git` for a blocklisted package such as `jupyterlab-git`; JupyterLab accepts the install request even though pip resolves the variant to the same package. This has security implications only for deployments that combine all of the following: - an allowlist/blocklist configured with the intent of restricting which packages users can install; - the (default) PyPI Extension Manager enabled; and - kernels and terminals disabled or delegated to remote hosts (otherwise a user with kernel access can install packages directly regardless of this check) ### Impact The vulnerability lets an authenticated user install a package the operator specifically intended to block, defeating the allowlist/blocklist control. Because extensions in principle allow for arbitrary code execution, this vulnerability enables untrusted users to impact the integrity and availability of the jupyter-server instance that was provisioned to them. The user already has access to their own single-user server's data, so installing an extension grants no new read access. In particular, the integrity of data can be impacted, and any hardening or restrictions on permitted user actions (download/upload limits) within the single-user server can be circumvented. Availability impact on a JupyterHub deployment is limited: while a user can be expected to exhaust their own kernel pod's resources, this vulnerability makes it easier to also exhaust the single-user server resources or generate more requests to shared resources; where limits are absent, resource exhaustion could potentially degrade the wider deployment. ### Patches JupyterLab [`v4.6.2`](https://github.com/jupyterlab/jupyterlab/releases/tag/v4.6.2) and [`v4.5.10`](https://github.com/jupyterlab/jupyterlab/releases/tag/v4.5.10) contain the patch. Users of applications that depend on JupyterLab, such as Notebook v7+, should update `jupyterlab` package too. ### Workarounds No action is required for deployments that do not have a custom allow/block list configured. Deployments wanting to disable programmatic extension installation entirely can switch to the read-only extension manager: ```bash --LabApp.extension_manager=readonly ``` or the following traitlet: ```python c.LabApp.extension_manager = 'readonly' ``` You can confirm that the read-only manager is in use from GUI: <img width="293" height="293" alt="image" src="https://github.com/user-attachments/assets/8016c809-633e-4ed0-a5bc-6bc4793caa0f" />
Exploitation Scenario
A managed JupyterHub deployment used for an internal ML training program blocks the `jupyterlab-git` extension via `blocked_extensions_uris` because it exposes repository credentials the operator doesn't want single-user servers to access, and disables terminal/kernel shell access to enforce this and similar policies. An authenticated data-science trainee who wants that functionality anyway requests installation of `JupyterLab.Git` — a spelling pip treats as identical to the blocked package but JupyterLab's weaker normalization treats as distinct — and the extension manager approves it. The extension installs and runs with the privileges of the user's single-user server, giving the trainee the exact capability the operator tried to block, and by extension demonstrating that any other blocklisted extension (not just this example) can be reached the same way, undermining the platform's package-governance control.
Weaknesses (CWE)
CWE-178 Improper Handling of Case Sensitivity
Primary
CWE-180 Incorrect Behavior Order: Validate Before Canonicalize
Primary
CWE-178 — Improper Handling of Case Sensitivity: The product does not properly account for differences in case sensitivity when accessing or determining the properties of a resource, leading to inconsistent results.
- [Architecture and Design] Avoid making decisions based on names of resources (e.g. files) if those resources can have alternate names.
- [Implementation] Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does. When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue." Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylis
Source: MITRE CWE corpus.
References
- github.com/advisories/GHSA-89vp-jrxv-24w8
- github.com/jupyterlab/jupyterlab/commit/be9303f5bcd5308eaeae953c5a3c903046682c2c
- github.com/jupyterlab/jupyterlab/commit/f1beab4a2027af4719d6edc07d52d6cf5a39a432
- github.com/jupyterlab/jupyterlab/pull/19184
- github.com/jupyterlab/jupyterlab/pull/19185
- github.com/jupyterlab/jupyterlab/pull/19186
- github.com/jupyterlab/jupyterlab/security/advisories/GHSA-89vp-jrxv-24w8
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-23537 9.1 Feast: unauth file write to RCE via /save-document
Same package: jupyter CVE-2026-54527 9.0 jupyterlab-git: stored XSS escalates to full RCE
Same package: jupyter CVE-2026-44727 9.0 jupyter-server: stored XSS yields kernel RCE
Same package: jupyter