GHSA-89vp-jrxv-24w8: JupyterLab: extension blocklist bypass via name mismatch

GHSA-89vp-jrxv-24w8 MEDIUM
Published July 22, 2026
CISO Take

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.

Sources: NVD GitHub Advisory OpenSSF CISA KEV

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?

Authenticated access
An adversary or insider already holds valid credentials on a JupyterLab/JupyterHub deployment where kernels and terminals are locked down and an extension blocklist is enforced.
AML.T0012
Blocklist evasion
The user requests installation of a PyPI-equivalent name variant (e.g. "JupyterLab.Git") of a blocked package, which JupyterLab's weaker normalization fails to recognize as matching the blocklist entry.
Unauthorized extension install
JupyterLab approves the install and pip resolves the variant to the actual blocked package, which then executes with the privileges of the user's single-user server.
AML.T0011.001
Impact
The installed extension lets the user circumvent operator-enforced restrictions (e.g. upload/download limits) and can affect the integrity and availability of the single-user server and, where limits are absent, shared JupyterHub resources.

What systems are affected?

Package Ecosystem Vulnerable Range Patched
Jupyter pip >= 4.6.0, <= 4.6.1 4.6.2
13.4K OpenSSF 5.8 1.9K dependents Pushed 9d ago 61% patched ~30d to patch Full package profile →

Do you use Jupyter? You're affected.

How severe is it?

CVSS 3.1
N/A
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
Moderate

What should I do?

1 step
  1. 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.

How is it classified?

Auth Bypass Code Execution Plugin Framework AML.T0010.001

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Article 15 - Accuracy, robustness and cybersecurity
ISO 42001
A.6.2.2 - AI system operational planning and control
NIST AI RMF
GOVERN 1.5 - Risk management processes are in place to monitor third-party components

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

training pipelinesnotebook-based ML development environmentsmulti-tenant JupyterHub deployments

MITRE ATLAS Techniques

AML.T0010.001 AI Software

Compliance Controls Affected

EU AI Act: Article 15
ISO 42001: A.6.2.2
NIST AI RMF: GOVERN 1.5

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: 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.

Timeline

Published
July 22, 2026
Last Modified
July 22, 2026
First Seen
July 23, 2026

Related Vulnerabilities