GHSA-RV4M-XM3F-3CCQ

Vulnerability from github – Published: 2026-10-19 16:49 – Updated: 2026-10-19 16:49
VLAI
Summary
Mercury: Unauthenticated Remote Code Execution via /api/kernels
Details

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/<id>/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).

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.2.5"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "mercury"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.2.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-111058"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-862"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-19T16:49:08Z",
    "nvd_published_at": null,
    "severity": "CRITICAL"
  },
  "details": "Mercury runs a JupyterLab server with **anonymous access by default** (`mercury_app/__main__.py` sets `--IdentityProvider.token=\u0027\u0027` 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.\n\n## The vulnerability\n`/api/kernels` is **NOT** in the blocklist (and cannot be \u2014 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:\n\n```\nPOST /api/kernels {\"name\":\"python3\"}        -\u003e 201, returns kernel id\nopen websocket /api/kernels/\u003cid\u003e/channels\nsend an execute_request with arbitrary code -\u003e arbitrary Python execution = RCE\n```\n\n## Distinct from GHSA-f8c7-rwf9-fmgm (incomplete fix)\nGHSA-f8c7 was \"Unauthenticated RCE via `/api/terminals`\" \u2014 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.\n\n## Runtime-proven (on the patched version)\nOn **mercury 3.2.4** \u2014 the release that fixed GHSA-f8c7 \u2014 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.\n\n## Impact\nUnauthenticated, network-reachable arbitrary code execution as the Mercury server process user on every default deployment \u2014 complete compromise of the host/container and any data/secrets it can reach. \n\n## Fix\nThe 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\u0027s own controlled execution flow.\n\n## Dedup (3-method)\nOSV.dev CLEAN(0) for `mercury` and `mljar-mercury`; the repo\u0027s 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=\u0027\u0027` default; `patch_kernel_websocket_handler` does no execute filtering).\n\nFinder: Abdullah Kareem (GitHub: CyberKareem).",
  "id": "GHSA-rv4m-xm3f-3ccq",
  "modified": "2026-10-19T16:49:08Z",
  "published": "2026-10-19T16:49:08Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/mljar/mercury/security/advisories/GHSA-rv4m-xm3f-3ccq"
    },
    {
      "type": "WEB",
      "url": "https://github.com/mljar/mercury/commit/73a40ceb0becf057f495a5738ad7f5a5222a53e1"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/mljar/mercury"
    },
    {
      "type": "WEB",
      "url": "https://github.com/mljar/mercury/releases/tag/3.2.6"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Mercury: Unauthenticated Remote Code Execution via /api/kernels"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.