GHSA-whvh-wf3x-g77j: JupyterLab: missing await skips extension allowlist check

GHSA-whvh-wf3x-g77j LOW
Published July 22, 2026
CISO Take

A missing `await` in JupyterLab's `PyPIExtensionManager.install()` means the allowlist/blocklist check silently never runs, so calls to this method don't actually enforce package restrictions — the only visible symptom was a RuntimeWarning in logs, not a crash. This is a low-severity defense-in-depth gap, not a directly exploitable flaw in stock JupyterLab: the HTTP API and Extension Manager UI perform their own separate, correctly-awaited check before ever calling `install()`, so out-of-the-box deployments are unaffected. It only matters for organizations that built custom extensions or downstream integrations calling `install()` directly with user-influenced package names, and that deliberately disabled kernels/terminals to force all package installation through that one gate — a pattern seen in locked-down, multi-tenant JupyterHub-style AI/ML notebook platforms. There is no known exploit code, it's not in CISA KEV, and EPSS data is unavailable, consistent with its low real-world exploitation likelihood. Action: upgrade to JupyterLab v4.6.2 / v4.5.10 (and update `notebook` if running v7+, since it depends on jupyterlab), or set `c.LabApp.extension_manager = 'readonly'` to disable programmatic installs entirely if custom `install()` call sites can't be updated immediately.

Sources: GitHub Advisory OpenSSF ATLAS

What is the risk?

Low. The CVSS 3.1 vector (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:N) reflects zero confidentiality/integrity/availability impact on its own — this is purely a control-bypass bug whose real-world consequence depends entirely on what a downstream deployer built on top of `install()`. Stock JupyterLab is not exposed because the HTTP API path performs its own independent, correctly-awaited allowlist check. Exploitability requires a fairly specific and unusual configuration: a custom extension calling `install()` directly with attacker-influenced input, an allowlist/blocklist actually configured with security intent, and kernels/terminals disabled so that this is the only install vector available (otherwise a user with kernel access could just install packages directly, making the check moot anyway). No public exploit, no Nuclei template, not in CISA KEV — this is a quiet, narrow-scope fix rather than an urgent one.

How does the attack unfold?

Restricted deployment precondition
A JupyterHub-style multi-tenant platform disables kernel/terminal access and routes package installs only through a custom extension calling PyPIExtensionManager.install() directly.
Bypass allowlist check
A user requests a blocklisted or non-allowlisted package; the missing await means the allow/block coroutine never executes, so the check silently fails open.
AML.T0010.001
Unauthorized package install
The disallowed or malicious package installs into the shared notebook environment despite the configured restriction.
AML.T0011.001
Code execution in kernel
Install-time or import-time code from the unauthorized package executes within the shared ML kernel, giving the attacker a foothold in the training/notebook environment.

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 →
Jupyter Notebook pip — No patch
13.4K OpenSSF 5.8 3.0K dependents Pushed 9d ago 85% patched ~92d to patch Full package profile →

How severe is it?

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

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC Low
PR Low
UI None
S Unchanged
C None
I None
A None

What should I do?

1 step
  1. 1) Upgrade to JupyterLab v4.6.2 or v4.5.10; if running Notebook v7+ (which depends on jupyterlab), update that package too. 2) If immediate upgrade isn't possible and programmatic extension installation isn't needed, set c.LabApp.extension_manager = 'readonly' (or --LabApp.extension_manager=readonly) to disable install-capable extension management entirely — confirm via the GUI that the read-only manager is active. 3) Audit any internal/custom extensions or integrations that call PyPIExtensionManager.install() directly; do not assume it self-enforces an allowlist — perform the allow/block check explicitly in the calling code as well. 4) Detection: the only runtime symptom pre-patch is RuntimeWarning: coroutine 'is_install_allowed' was never awaited in logs — grep application/server logs for this string to identify still-vulnerable, unpatched instances actively hitting the code path.

How is it classified?

Auth Bypass Supply Chain Code Execution Plugin Framework AML.T0010.001 AML.T0011.001

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Article 15 - Accuracy, robustness and cybersecurity
NIST AI RMF
GOVERN 6.1 - Third-party and supply chain risks are identified and managed
OWASP LLM Top 10
LLM05:2025 - Supply Chain Vulnerabilities

Frequently Asked Questions

What is GHSA-whvh-wf3x-g77j?

A missing `await` in JupyterLab's `PyPIExtensionManager.install()` means the allowlist/blocklist check silently never runs, so calls to this method don't actually enforce package restrictions — the only visible symptom was a RuntimeWarning in logs, not a crash. This is a low-severity defense-in-depth gap, not a directly exploitable flaw in stock JupyterLab: the HTTP API and Extension Manager UI perform their own separate, correctly-awaited check before ever calling `install()`, so out-of-the-box deployments are unaffected. It only matters for organizations that built custom extensions or downstream integrations calling `install()` directly with user-influenced package names, and that deliberately disabled kernels/terminals to force all package installation through that one gate — a pattern seen in locked-down, multi-tenant JupyterHub-style AI/ML notebook platforms. There is no known exploit code, it's not in CISA KEV, and EPSS data is unavailable, consistent with its low real-world exploitation likelihood. Action: upgrade to JupyterLab v4.6.2 / v4.5.10 (and update `notebook` if running v7+, since it depends on jupyterlab), or set `c.LabApp.extension_manager = 'readonly'` to disable programmatic installs entirely if custom `install()` call sites can't be updated immediately.

Is GHSA-whvh-wf3x-g77j actively exploited?

No confirmed active exploitation of GHSA-whvh-wf3x-g77j has been reported, but organizations should still patch proactively.

How to fix GHSA-whvh-wf3x-g77j?

1) Upgrade to JupyterLab v4.6.2 or v4.5.10; if running Notebook v7+ (which depends on jupyterlab), update that package too. 2) If immediate upgrade isn't possible and programmatic extension installation isn't needed, set `c.LabApp.extension_manager = 'readonly'` (or `--LabApp.extension_manager=readonly`) to disable install-capable extension management entirely — confirm via the GUI that the read-only manager is active. 3) Audit any internal/custom extensions or integrations that call `PyPIExtensionManager.install()` directly; do not assume it self-enforces an allowlist — perform the allow/block check explicitly in the calling code as well. 4) Detection: the only runtime symptom pre-patch is `RuntimeWarning: coroutine 'is_install_allowed' was never awaited` in logs — grep application/server logs for this string to identify still-vulnerable, unpatched instances actively hitting the code path.

What systems are affected by GHSA-whvh-wf3x-g77j?

This vulnerability affects the following AI/ML architecture patterns: notebook-based ML development environments, multi-tenant AI development platforms (JupyterHub-style), training pipelines.

What is the CVSS score for GHSA-whvh-wf3x-g77j?

No CVSS score has been assigned yet.

What is the AI security impact?

Affected AI Architectures

notebook-based ML development environmentsmulti-tenant AI development platforms (JupyterHub-style)training pipelines

MITRE ATLAS Techniques

AML.T0010.001 AI Software
AML.T0011.001 Malicious Package

Compliance Controls Affected

EU AI Act: Article 15
NIST AI RMF: GOVERN 6.1
OWASP LLM Top 10: LLM05:2025

What are the technical details?

Original Advisory

The extension allowlist/blocklist check inside `PyPIExtensionManager.install()` was not enforced due to a missing await. For purposes of JupyterLab this was a secondary defense-in-depth check: `install()` was intended to enforce the allowlist/blocklist itself for any future uses and users calling this method directly (in addition to the separate check handling requests arriving through the HTTP API). The only runtime symptom was a `RuntimeWarning: coroutine 'is_install_allowed' was never awaited.` This has security implications only for deployments that combine all of the following: - a custom extension or downstream integration that imports `PyPIExtensionManager` and calls `install()` directly with a package name influenced by untrusted user input (the stock JupyterLab HTTP handler is not affected - it performs its own awaited allowlist check before calling `install()`); - 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, so that the custom extension's `install()` call is the only available package-install vector (otherwise a user with kernel access can install packages directly regardless of this check) ### Impact Low. No exposure for stock JupyterLab: the HTTP API and Extension Manager UI enforce the listing through a separate, correctly awaited check. The gap affected only custom extensions or downstream integrations that called the public `install()` method directly and relied on it to self-enforce. ### 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 only expose extension management through the JupyterLab HTTP API / Extension Manager UI, as that path was already enforcing the listing via the handler's own check. 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

An organization runs a shared JupyterHub-based ML training platform where, for security, admins disabled direct kernel and terminal access for data scientists and instead built a custom extension that lets users request approved packages, calling `PyPIExtensionManager.install()` directly and trusting it to enforce a configured package blocklist. A user (or an attacker who has obtained low-privilege notebook access) requests installation of a blocklisted or unapproved package — for example a typosquatted or supply-chain-compromised PyPI package — through this extension. Because the allowlist check coroutine is never awaited, it never actually runs, so the block silently fails open and the package installs anyway. The malicious package's install-time code (or code imported afterward) executes within the shared notebook kernel, giving the attacker code execution inside the ML training environment and a foothold to pivot to datasets, credentials, or other tenants' notebooks on the same platform.

Weaknesses (CWE)

CWE-284 — Improper Access Control: The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.

  • [Architecture and Design, Operation] Very carefully manage the setting, management, and handling of privileges. Explicitly manage trust zones in the software.
  • [Architecture and Design] Compartmentalize the system to have "safe" areas where trust boundaries can be unambiguously drawn. Do not allow sensitive data to go outside of the trust boundary and always be careful when interfacing with a compartment outside of the safe area. Ensure that appropriate compartmentalization is built into the system design, and the compartmentalization allows for and reinforces privilege separation functionality. Architects and designers should rely on the principle of least privilege to decide the appropriate time to use privileges and the time to drop privileges.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:N

Timeline

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

Related Vulnerabilities