
Proof-of-concept exploit for CVE-2026-39987, a pre-authentication RCE in Marimo's /terminal/ws WebSocket endpoint, providing unauthenticated PTY shell access.
Marimo <= 0.20.4 is affected by a pre-authentication RCE vulnerability in the /terminal/ws WebSocket endpoint.
The endpoint checks the application mode and terminal support, but does not validate authentication before accepting the WebSocket connection. It then creates a PTY shell, allowing an unauthenticated attacker to execute commands with the privileges of the Marimo process.
Unlike other WebSocket endpoints that call validate_auth(), the vulnerable terminal endpoint accepts the connection directly:
if app_state.mode != SessionMode.EDIT:
await websocket.close(...)
return
if not supports_terminal():
await websocket.close(...)
return
await websocket.accept()
child_pid, fd = pty.fork()
The missing authentication check allows unauthenticated access to the PTY.
<= 0.20.4The included CVE-2026-39987.py client connects to:
/terminal/ws
Interactive mode:
python3 CVE-2026-39987.py -i
Single command:
python3 CVE-2026-39987.py "id"
Configure the target by replacing DEFAULT_HOST in the script.
Successful exploitation can provide an unauthenticated PTY shell and arbitrary command execution as the Marimo server user.