A missing comma opens Mercury's terminal endpoint: two CRITICAL unauth RCEs

A single missing comma in a Python list silently disabled one rule of Mercury's endpoint blocklist, leaving /api/terminals open. Two CRITICAL unauthenticated remote-code-execution flaws let any reachable network client run code on the host with no credentials.

Share
A self-hosted server on a desk with a laptop showing an open terminal prompt and no password field, rendered with AI.
A self-hosted server on a desk with a laptop showing an open terminal prompt and no password field, rendered with AI.

A single missing comma in a Python list is enough to disable a security control that still looks intact. In Mercury, a self-hosted framework that turns a Jupyter notebook into a shareable interactive web app, that missing comma removed one rule from a blocklist and left /api/terminals open to anyone who could reach the server.

On 2026-10-19, two CRITICAL unauthenticated remote-code-execution flaws were disclosed in Mercury. Both let a network client, with no credentials, run code on the host. The tool is popular (about 4,357 GitHub stars) and self-hosted, so the person running it decides how the server is reached.

The one-character bug

The first, CVE-2026-111057 (NVD CVSS 10.0), lives in mercury_app/block_handler.py. Mercury's default posture is anonymous access with a blocklist of dangerous endpoints. One rule in that list was meant to block /api/terminals, which spawns a full interactive OS shell.

A missing comma in the BLOCKED_PATTERNS list merged the /lab rule and the /api/terminals rule into a single invalid pattern. The /api/terminals rule stopped matching anything. The blocklist still looked intact; one of its rules was a no-op. Any unauthenticated client that POSTed to /api/terminals got a shell on the host.

This is the failure mode of a deny-list: the control appears present, but a typo quietly removes one of its teeth. The vulnerable range is >= 3.0.0, <= 3.2.3. The comma was restored in v3.2.4.

The tokenless default

The second, CVE-2026-111058 (NVD CVSS 9.8), is about the default credential posture. Mercury runs a JupyterLab server with an empty token by default, so the server is anonymous until you set a token. /api/kernels is not in the blocklist (it has to stay open for notebook execution), and the idle-timeout patch on the kernel websocket handler performs no filtering of execute_request. An unauthenticated client can POST to /api/kernels and run arbitrary code.

The fix does not add authentication. It adds an execution policy that restricts what anonymous clients can do. The default is still tokenless; safety now depends on the blocklist plus the execution policy being correct.

The exposure is the point

The third angle is the shape of the tool itself. Mercury's value proposition is to publish an interactive notebook to a URL. That same property is what makes it dangerous when the server is reachable without an external access control. Behind a VPN, reverse-proxy auth, or firewall, the flaws are less reachable. Exposed directly, a single request yields a shell or arbitrary code execution, a foothold for lateral movement.

What is fixed, and what is still open

As of 2026-10-20, no published release names these CVEs. The latest release is 3.2.11 (2026-09-10), which predates the 2026-10-19 disclosure. The fix code is present in the repository history (the comma in v3.2.4; the kernel-execution policy from v3.2.5), but whether a release that explicitly addresses the two RCEs has shipped is unconfirmed.

There is a minor discrepancy on the exact fixed-version boundary for the kernel RCE. The advisory says vulnerable <= 3.2.5, but code inspection shows the kernel-execution policy first appears in v3.2.5 (absent in v3.2.4), which would make v3.2.5 the first fixed release and the vulnerable range <= 3.2.4. The advisory's patched_versions field is null, so the boundary is not pinned by the advisory.

A third, lower-severity flaw was disclosed in the same batch: CVE-2026-111059 (medium), a stored/DOM XSS in mr.Markdown, sanitized by default in 3.2.11. There is no KEV listing and no confirmed in-the-wild exploitation for either CVE as of 2026-10-20.

Defensive guidance

  • Upgrade to the latest release (3.2.11) and set a Jupyter token.
  • Put the server behind an external access control (VPN, reverse-proxy auth, or firewall). Treat the app's internal blocklist as a secondary control.
  • Confirm the current recommended version with the vendor.

Sources

This article was drafted with AI/LLM assistance and reviewed by a human before publication. All factual claims were checked against the public sources cited above. The feature image was generated with AI. See How we use AI for the full workflow.

Topics: