- Endpoint /terminal/ws của Marimo quên gọi validate_auth() — attacker chưa đăng nhập vẫn spawn được PTY shell.
- CVSS 9.3, exploit in-the-wild chỉ 9h41m sau disclosure.
- Nâng cấp 0.23.0 ngay.
TL;DR
CVE-2026-39987 là lỗ hổng pre-authentication RCE trong Marimo — Python reactive notebook phổ biến trong AI/ML toolchain. Endpoint WebSocket /terminal/ws bỏ sót validate_auth(), cho phép bất kỳ ai có network access spawn thẳng PTY shell với quyền process của Marimo (thường là root trong container). CVSS 9.3 Critical. Advisory công bố 2026-04-08, exploit in-the-wild đầu tiên ghi nhận sau 9 giờ 41 phút. Bản vá: Marimo 0.23.0.
What's new
Ngày 2026-04-08, Marimo team publish advisory GHSA-2679-6mx9-h9xc (reporter: q1uf3ng) cảnh báo một endpoint WebSocket duy nhất đang cho phép thực thi lệnh hệ thống mà không cần credentials. Trong khi các endpoint khác như /ws (notebook kernel) gọi WebSocketConnectionValidator.validate_auth() đầy đủ, handler của /terminal/ws chỉ kiểm tra running mode + platform support rồi nhảy thẳng vào websocket.accept() và pty.fork().
Điều đáng lo không chỉ là bản thân lỗ hổng mà còn là tốc độ weaponize. Theo Sysdig, honeypot của họ đã ghi nhận lần exploit thật đầu tiên lúc 07:31 UTC ngày 2026-04-09 — cách advisory đúng 9 giờ 41 phút — và credential theft hoàn tất trong dưới 3 phút.
Why it matters
Marimo sống ở vị trí rất nhạy cảm trong dev stack: máy của data scientist, CI runner, Jupyter-style sidecar trong k8s AI pod. Những môi trường này thường mount sẵn ~/.aws, SSH keys, HuggingFace tokens, OpenAI keys, connection string của vector DB. Một pre-auth shell tại đây đồng nghĩa attacker có toàn bộ credential kit của team AI/ML — lateral movement vào S3, RDS, internal inference API chỉ là chuyện vài lệnh curl tiếp theo.
Đây cũng là một case study điển hình cho xu hướng AI-accelerated exploitation: không cần PoC public, attacker vẫn weaponize được chỉ từ wording của advisory trong vòng chưa tới nửa ngày.
Technical facts
| Property | Value |
|---|---|
| CVE ID | CVE-2026-39987 |
| Advisory | GHSA-2679-6mx9-h9xc |
| CVSS 3.1 Score | 9.3 (Critical) |
| CWE | CWE-306 Missing Authentication for Critical Function |
| Affected versions | ≤ 0.20.4 (theo advisory chính thức) |
| Patched version | 0.23.0 |
| Vulnerable endpoint | /terminal/ws |
| Attack complexity | Low — không auth, không user interaction |
| Exploit primitive | WebSocket connect → pty.fork() → interactive shell |
Lõi bug rất ngắn — handler đại khái như sau:
@router.websocket("/terminal/ws")
async def terminal_ws(websocket: WebSocket):
# chỉ check mode + platform support
await websocket.accept()
child_pid, fd = pty.fork() # spawn PTY shellKhông có validate_auth(), không có token/cookie check, không có origin check. Một client Python vài dòng là đủ:
import websocket
ws = websocket.create_connection("ws://TARGET:PORT/terminal/ws")
ws.send("id\n")
print(ws.recv())Comparison
Lớp lỗi này khá giống các vụ Jupyter terminal auth bypass trong quá khứ, nhưng tác động thực tế lớn hơn ở 2 điểm:
- Container blast radius: Marimo thường chạy trong AI/ML container với mount secrets, network egress rộng. Shell lấy được hay là
uid=0. - Auth inconsistency trong cùng codebase:
/wsgọivalidate_auth(),/terminal/wsthì không. Đây là dạng bug khó audit bằng mắt — cần grep tất cả route và diff middleware/decorator giữa chúng.
Who is affected
- AI/ML engineers chạy
marimo editbind0.0.0.0để demo từ xa. - Data scientists expose notebook qua ngrok, Cloudflare Tunnel, Tailscale Funnel mà không thêm auth layer.
- Marimo deploy trong k8s/Docker với Service/Ingress public (dashboard nội bộ, shared sandbox).
- Bất kỳ host nào chưa nâng 0.23.0 và có cổng Marimo reachable từ attacker.
Post-exploit telemetry từ Sysdig cho thấy attacker target cực kỳ có chủ đích: đọc thẳng .env tìm AWS access key, tìm SSH key trong ~/.ssh, check bash_history khi quay lại. Không drop cryptominer rõ rệt — đây là operator săn credential, không phải commodity botnet.
Limitations & mitigation
- Điều kiện khai thác: cần reachability mạng tới
/terminal/ws. Marimo bind mặc định127.0.0.1tương đối an toàn, nhưng nhiều hướng dẫn blog/tunnel khuyên bind0.0.0.0→ lộ ngay. - Fix chính thức: upgrade lên 0.23.0 hoặc mới hơn.
pip install -U marimohoặc pin lại version trong lockfile. - Chặn tạm thời (nếu chưa upgrade được): block path
/terminal/wsở reverse proxy (nginx/Caddy/Traefik), bật auth tunnel (Cloudflare Access, Tailscale ACL), firewall port Marimo về chỉ IP nội bộ. - Audit: rotate toàn bộ secrets có trên host (AWS, GCP, OpenAI, GitHub PAT, SSH keys) nếu nghi đã expose. Grep log reverse proxy tìm request tới
/terminal/wstừ IP lạ. - Detection: có Nuclei template public (
CVE-2026-39987.yamltrong rxerium-templates) để scan fleet nội bộ trước khi attacker làm hộ.
What's next
Sự việc Marimo là một tín hiệu rõ: cửa sổ vá lỗi cho OSS tool đang co lại dưới 1 ngày. Với tooling AI/ML — nơi dev thường bind port rộng rãi để "cho nhanh" và chứa sẵn credential đắt — đây là cặp đôi rủi ro điển hình. Advisory của Marimo được vá nhanh, nhưng trách nhiệm deploy an toàn vẫn thuộc về người chạy service.
Khuyến nghị hành động trong 24 giờ tới: (1) kiểm kê mọi Marimo instance trong tổ chức, (2) upgrade 0.23.0, (3) rotate secret nếu có dấu hiệu truy cập lạ, (4) thêm auth layer (reverse proxy SSO, Tailscale) trước notebook dev.
Nguồn: GitHub Security Advisory, Resecurity, Sysdig, The Hacker News, BleepingComputer.