- Lỗ hổng CVSS 9.3 trong marimo cho phép mở 1 WebSocket tới /terminal/ws là có shell root tương tác.
- Sysdig ghi nhận khai thác thực tế sau 9h41, credential theft xong trong dưới 3 phút, hoàn toàn không cần PoC public.
TL;DR
CVE-2026-39987 là lỗ hổng pre-auth RCE trong marimo — reactive Python notebook framework (~20k sao GitHub). Endpoint WebSocket /terminal/ws quên gọi validate_auth(), attacker chỉ cần mở 1 WebSocket handshake là nhận full PTY shell với quyền của process marimo (thường là root trong Docker mặc định).
CVSS v4.0 9.3 (Critical). Sysdig ghi nhận exploit thực tế chỉ 9 giờ 41 phút sau khi advisory công bố, credential theft hoàn tất dưới 3 phút — và không có PoC public nào tồn tại tại thời điểm đó. Endor Labs quét thử 186 instance internet-facing, 30 instance (~16%) chấp nhận handshake không auth. Fix: upgrade marimo >= 0.23.0 ngay lập tức.
Chuyện gì vừa xảy ra
Ngày 2026-04-08, advisory GHSA-2679-6mx9-h9xc được công bố cho marimo. Ngày 2026-04-09, CVE-2026-39987 lên NVD. Sáng hôm sau, honeypot fleet của Sysdig Threat Research Team đã ghi nhận exploit thành công — nhanh hơn gấp đôi so với vụ Langflow (CVE-2026-33017) vài tuần trước đó, vốn đã xác lập kỷ lục 20 giờ.
Lần này, attacker không đợi ai. Họ dựng exploit trực tiếp từ đoạn mô tả trong advisory, không cần PoC, không cần reverse engineering — dấu hiệu khá rõ cho thấy threat actor đang dùng AI để vũ khí hóa lỗ hổng ngay khi disclosure.
Root cause: thiếu 1 dòng validate_auth()
Marimo có nhiều WebSocket endpoint. Endpoint session chính /ws xử lý auth đúng chuẩn — gọi WebSocketConnectionValidator.validate_auth() trước khi chấp nhận connection. Nhưng endpoint /terminal/ws (trong marimo/_server/api/endpoints/terminal.py) đi theo một path khác:
- Kiểm tra đang ở edit mode?
- Kiểm tra platform có hỗ trợ PTY?
- Gọi thẳng
pty.fork()— spawn PTY shell.
Bước auth bị bỏ qua hoàn toàn. Starlette AuthenticationMiddleware có đánh dấu connection là unauthenticated, nhưng không tự reject WebSocket upgrade — việc enforce auth là trách nhiệm ở cấp endpoint, và terminal handler thì không làm.
Kết quả: gửi đúng WebSocket handshake tới /terminal/ws, attacker cầm được PTY interactive shell tương đương ssh vào server. Không token. Không session. Không user interaction. CWE-306 sách giáo khoa.
Technical facts
| Property | Value |
|---|---|
| CVE ID | CVE-2026-39987 |
| CVSS v4.0 | 9.3 (Critical) |
| Vector | AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H |
| Loại | Pre-Auth RCE via WebSocket |
| CWE | CWE-306 (Missing Authentication for Critical Function) |
| Affected | marimo < 0.23.0 |
| Fixed | marimo 0.23.0 |
| GHSA | GHSA-2679-6mx9-h9xc |
| NVD published | 2026-04-09 |
| Shodan dork | http.favicon.hash:-1864630356 |
So sánh: tốc độ weaponize đang sụp đổ
Hai vụ pre-auth RCE gần nhất trên hệ sinh thái Python notebook / AI tooling:
| Vụ | Public PoC khi exploit? | Thời gian disclosure → first exploit |
|---|---|---|
| Langflow CVE-2026-33017 | Không | ~20 giờ |
| marimo CVE-2026-39987 | Không | 9 giờ 41 phút |
Marimo không phải phần mềm "hot". Chỉ ~20k sao GitHub — niche hơn nhiều so với Langflow hay n8n. Nhưng vẫn bị target trong vòng 12 tiếng. Kết luận của Sysdig khá khô: "Attackers monitor all advisories broadly and can weaponize flaws within hours, likely aided by AI." Security-by-obscurity đã chết — giả định niche tool thì an toàn là sai.
Real-world: attacker làm gì sau khi vào
Từ honeypot data của Sysdig trong 12h đầu:
- 125 IP scan/probe port & HTTP
- 1 IP tiến tới exploit thật sự
- Attacker validate flaw bằng scripted PoC trước, sau đó thao tác tay — hành vi của operator có chủ đích, không phải bot
- Nhiều session trong 90 phút, tập trung đánh cắp
.envfiles & SSH keys - Không deploy persistence hay malware trong giai đoạn này — chỉ lấy credential rồi rút
Song song, Resecurity báo cáo biến thể khác dùng lỗ hổng này để deliver NKAbuse malware host trên Hugging Face Spaces.
Blast radius: tại sao đây là vấn đề cloud
Marimo hiếm khi chạy đơn độc. Nó thường co-located với:
- AI/ML orchestration platforms (LangChain, Airflow)
- LLM front-ends
- Source code repos & CI runners
- Reverse proxy, bastion, dev tools
Trên cùng VM, tất cả service này thường share .env với cloud credentials (AWS/GCP/Azure keys). Một WebSocket handshake có thể bridging thẳng sang cloud account takeover — không phải scenario giả định, đã được Endor Labs mô tả là hệ quả có xác suất rất cao với setup điển hình.
Endor Labs cũng chạy recon trên 186 URL marimo internet-reachable trong mẫu: 30 (~16%) chấp nhận unauthenticated WebSocket upgrade tới /terminal/ws. Họ dừng ở handshake, không execute command — nhưng đó chính là bước cuối trước khi shell mở. Ước tính tổng số instance còn vulnerable trên internet: hàng chục đến hàng trăm.
Mitigation & khuyến nghị
Làm ngay, theo thứ tự:
- Upgrade marimo >= 0.23.0. Không thương lượng.
pip install --upgrade marimo. Patch chỉ đơn giản thêmvalidate_auth()vào terminal WebSocket handler (PR #9098). - Không expose marimo ra untrusted network. Dùng VPN, private subnet, bastion, hoặc reverse proxy có auth riêng.
- Không bind
0.0.0.0trừ khi bắt buộc và đã firewall cứng. - Giám sát traffic tới
/terminal/ws, process tree bất thường, outbound connection lạ. Nuclei template có sẵn:rxerium-templates/2026/CVE-2026-39987.yaml. - Nếu instance từng expose public — giả định đã bị compromise. Rotate toàn bộ
.envsecrets, SSH keys, cloud credentials. Hunt persistence (cron, startup scripts, injected Python paths). - Chạy marimo với user non-root, drop Linux capabilities, dùng base image tối thiểu. (Phòng thủ lớp 2 — không thay thế việc patch.)
- Nếu không cần terminal: vô hiệu hóa route
/terminal/wshoàn toàn.
Bài học cho team dev
Vụ này không chỉ là 1 CVE của 1 tool. Đây là tín hiệu kép:
- Niche software ≠ safe. Threat actor đang monitor mọi advisory, kể cả tool 20k sao. Nếu bạn run một tool ít người biết nhưng có auth surface ra internet — bạn vẫn ở trên radar.
- WebSocket auth phải enforce per-endpoint. Middleware của Starlette (và các framework tương tự) không tự động reject WebSocket upgrade cho unauthenticated user — chỉ gắn flag. Audit từng handler, đừng tin "middleware sẽ lo".
- AI-assisted exploit dev đang rút ngắn window. 10 giờ từ disclosure tới weaponization đã là "chuẩn mới". Patch management dựa trên SLA theo ngày/tuần không còn đủ cho critical auth bypass.
- Notebook server là production asset. Cứ expose shell là gánh rủi ro cloud account. Cần classify lại trong threat model.
Nguồn: Endor Labs, The Hacker News, Security Affairs, Resecurity, BleepingComputer.