CVE-2026-39987 — Marimo pre-auth RCE

marimo before 0.23.0 exposes a pre-auth remote code execution path on /terminal/ws. The endpoint accepted WebSocket connections without validating authentication, allowing an unauthenticated attacker to obtain a PTY shell and run arbitrary commands.

NVD shows this CVE was added to CISA’s KEV catalog on 2026-04-23, which means active exploitation evidence exists and remediation should be expedited. Treat a reachable vulnerable notebook server as an incident candidate, not just a dependency bump.

When to use it

Use this recipe when a repository installs, images, deploys, or documents Marimo notebooks, shared notebook servers, demos, devcontainers, Codespaces, or remote workspaces. It is designed for source-code/deployment remediation, pre-auth RCE exposure review, notebook network-boundary hardening, credential rotation assessment, and evidence that vulnerable /terminal/ws endpoints are not reachable.

Inputs

  • Marimo version, Python dependency files, lockfiles, notebook images, devcontainer/CI/demo configs, launch commands, reverse-proxy policy, and SBOM or generated dependency reports.
  • Source/config paths that start Marimo, expose ports, enable terminal features, forward localhost, mount cloud/model/package/repository credentials, or document notebook access.
  • Regression or deployment checks for patched versions, authenticated access, private network binding, no exposed terminal endpoint, and safe dependency policy without probing /terminal/ws.
  • Boundary evidence: notebook users, exposed URLs, forwarded ports, runtime secrets, incident-review owner, image owners, logs, and rollout owner.

Affected versions

  • Vulnerable: marimo < 0.23.0
  • Fixed: marimo >= 0.23.0

Indicator-of-exposure

  • marimo is installed at a vulnerable version.
  • The service is reachable from untrusted networks.
  • Notebook or terminal functionality is exposed to shared users / internet.

Quick checks:

python -m pip show marimo
python - <<'PY'
import marimo
print(marimo.__version__)
PY
ss -lntp | rg ':2718|:8080|:80|:443'

Windows:

python -m pip show marimo
python -c "import marimo; print(marimo.__version__)"
netstat -ano | findstr ":2718 :8080 :80 :443"

Do not connect to /terminal/ws, attempt to obtain a shell, or print runtime environment variables during triage.

Remediation strategy

  • Upgrade immediately to marimo>=0.23.0 in every manifest, lockfile, image, notebook environment, and deployment artifact controlled by the repository.
  • Place the service behind strong authentication and reverse-proxy policy.
  • Restrict network reachability (VPN / private subnet / IP allow-list).
  • Add a non-exploit regression check that fails on resolved marimo <0.23.0.
  • Rotate credentials and secrets available to the marimo runtime if exposure was internet-facing or reachable by untrusted users.

The prompt

You are remediating CVE-2026-39987 (Marimo pre-auth RCE) in this repository or
runtime image. Produce exactly one of:

1. A reviewer-ready PR that upgrades marimo to a fixed version and adds basic
   hardening controls.
2. TRIAGE.md if no safe patch path exists in this codebase.

## Rules

- Fix only CVE-2026-39987 scope.
- Prefer the smallest safe version bump to `>=0.23.0`.
- Do not auto-merge.
- If internet-exposed runtime was vulnerable, include an incident-response
  checklist in the PR body.

## Steps

1. Detect current marimo version from lockfiles + environment metadata.
2. If marimo is absent or already `>=0.23.0`, stop with a short triage note.
3. Update dependency manifests and lockfiles to a fixed marimo version.
4. Search for marimo launch points and add a hardening note (auth + network
   boundary) in ops docs or deployment manifest comments, without unrelated
   refactors.
5. Add safe regression coverage or a CI/deploy guard that rejects marimo
   versions below `0.23.0` without probing `/terminal/ws`.
6. Run project tests/lint and any dependency/security scans.
7. Output:
   - PR title: `fix(sec): remediate CVE-2026-39987 in marimo`
   - PR body must include: affected version, fixed version, test output summary,
     whether the server was network-reachable, and operator follow-ups
     (credential rotation if exposed).

## Stop conditions

- Patch would require unsupported major stack migration.
- No lockfile / deterministic dependency mechanism exists.
- Verification would require connecting to `/terminal/ws`, obtaining a shell,
  or exposing runtime secrets.
- Tests fail due to unrelated pre-existing failures.

Output contract

  • A reviewer-ready PR or change request that upgrades Marimo, refreshes dependency/image artifacts, hardens notebook exposure, adds version/exposure checks, and documents credential/operator review.
  • Or a TRIAGE.md file that lists inspected dependencies/images/launchers, owner, observed version, network exposure boundary, required fix, and residual risk.
  • The output must include exact validation commands and must not connect to /terminal/ws, obtain shells, print environment variables, or expose runtime secrets.

Verification — what the reviewer looks for

  • Lockfile, manifest, image metadata, and generated dependency reports pin marimo to >=0.23.0.
  • No vulnerable marimo version remains in the dependency tree.
  • CI or deployment checks fail closed on marimo <0.23.0.
  • Tests/lint are green or failures are clearly pre-existing.
  • PR includes runtime hardening follow-ups if service was internet-reachable.

Watch for

  • Updating a local notebook environment while a remote dev image, shared workspace, or demo container still installs marimo <0.23.0.
  • Treating localhost binding as safe when Codespaces, devcontainers, SSH tunnels, or proxy previews forward the port.
  • Running marimo with cloud, model-provider, package, or repository-write tokens in the same environment used for interactive notebooks.
  • Verification that connects to /terminal/ws or prints runtime environment values instead of checking version and launch configuration safely.

References