GitHub Advisoryadvisory · PyPI

GHSA-rv4m-xm3f-3ccq Mercury: Unauthenticated Remote Code Execution via /api/kernels

CRITICAL Published 2026-10-19 Modified 2026-10-19 Official page ↗
Aliases
CVE-2026-111058
Ecosystem
PyPI
Packages
mercury
Severity
Critical
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weaknesses
CWE-862
Reviewed
2026-10-19

Affected packages

• PyPI mercury: < 3.2.6 → fixed in 3.2.6

Description

Mercury runs a JupyterLab server with anonymous access by default (`mercury_app/__main__.py` sets `--IdentityProvider.token=''` when no `--token`/`MERCURY_TOKEN` is given; when tokenless it also sets `--ServerApp.disable_check_xsrf=True`). It relies on a blocklist (`mercury_app/block_handler.py` `BLOCKED_PATTERNS`: `/lab`, `/api/terminals`, `/api/shutdown`, `/files`) to keep anonymous users off dangerous Jupyter endpoints. The vulnerability `/api/kernels` is NOT in the blocklist (and cannot be — Mercury needs kernels to run notebooks), and `patch_kernel_websocket_handler()` (`mercury_app/idle_timeout.py`) only tracks the idle-timeout: it wraps `on_message` to call `self.application._timeout_manager.touch()` and then invokes the original handler with no filtering of `execute_request`. So any unauthenticated network client can: ``` POST /api/kernels {"name":"python3"} -> 201, returns kernel id open websocket /api/kernels//channels send an execute_request with arbitrary code -> arbitrary Python execution = RCE ``` Distinct from GHSA-f8c7-rwf9-fmgm (incomplete fix) GHSA-f8c7 was "Unauthenticated RCE via `/api/terminals`" — a missing-comma blocklist bypass. Its fix (add the comma so `/api/terminals` is blocked) does NOT address `/api/kernels`, which remains exploitable. The blocklist approach is fundamentally unable to cover kernels, so this is not a variant that another blocklist entry fixes. Runtime-proven (on the patched version) On mercury 3.2.4 — the release that fixed GHSA-f8c7 — with the default (tokenless) config, as an unauthenticated client: `POST /api/terminals` returns 403 (the f8c7 fix is present), but `POST /api/kernels` returns 201; opening the kernel websocket and sending an `execute_request` executed attacker-supplied Python (ran `whoami` as the server process user and wrote a marker file `/tmp/PWNED_MERCURY_RCE`). Full unauthenticated remote code execution. Deterministic PoC (client script + notebook) included. Impact Unauthenticated, network-reachable arbitrary code execution as the Mercury server process user on every default deployment — complete compromise of the host/container and any data/secrets it can reach. Fix The blocklist cannot secure an anonymous kernel-backed server. Require real per-request authentication (a token or password) by default, or restrict the kernel message channel so anonymous websocket clients cannot issue `execute_request` outside Mercury's own controlled execution flow. Dedup (3-method) OSV.dev CLEAN(0) for `mercury` and `mljar-mercury`; the repo's only advisory (GHSA-f8c7-rwf9-fmgm) covers `/api/terminals` only (description does not mention kernels); no issue/PR describes the `/api/kernels` RCE (#219/#134/#262 are "add auth" feature requests that merely confirm anonymous-by-default). Sink independently confirmed on current HEAD (blocklist omits `/api/kernels`; `token=''` default; `patch_kernel_websocket_handler` does no execute filtering). Finder: Abdullah Kareem (GitHub: CyberKareem).

Related

Alias · CVE (1)

  • CVE-2026-111058 Mercury is a Python framework for sharing Jupyter notebooks as web applications and dashboards. vulnerability

Weakness · CWE (1)

  • CWE-862 Missing Authorization weakness

References