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 validate_auth() for authentication, the /terminal/ws endpoint only checks the running mode and platform support before accepting connections, completely skipping authentication verification.
Vulnerability Details
Root Cause: Terminal WebSocket Missing Authentication
marimo/_server/api/endpoints/terminal.py lines 340-356:
Compare with the correctly implemented /ws endpoint ( ws_endpoint.py lines 67-82):
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 validate_auth() calls.
The /terminal/ws endpoint has neither a @requires("edit") decorator nor a validate_auth() call, so unauthenticated WebSocket connections are accepted even when the auth middleware is active.
WebSocket connect to ws://TARGET:2718/terminal/ws (no auth needed)
websocket.accept() accepts the connection directly
pty.fork() creates a PTY child process
Full interactive shell with arbitrary command execution
Commands run as root in default Docker deployments
A single WebSocket connection yields a complete interactive shell.
Reproduction Environment
With auth enabled (server generates random access_token ), the exploit bypasses authentication entirely:
Suggested Remediation
Add authentication validation to /terminal/ws endpoint, consistent with /ws using WebSocketConnectionValidator.validate_auth()
Apply unified authentication decorators or middleware interception to all WebSocket endpoints
Terminal functionality should only be available when explicitly enabled, not on by default
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.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
