Apr 13, 2026 · 6 min read
A Python AI Notebook Had No Password on Its Terminal—Hackers Found It in 10 Hours
CVE-2026-39987 gave unauthenticated attackers root shell access to Marimo instances. Credential theft took under 3 minutes.
What Happened
Marimo, a popular Python reactive notebook framework with nearly 20,000 GitHub stars, shipped a terminal feature with no authentication on its WebSocket endpoint. Anyone who could reach the server could open a full interactive shell and execute commands as the Marimo process user, often root in default Docker configurations.
The flaw, tracked as CVE-2026-39987 with a CVSS score of 9.3, was disclosed on April 8, 2026. Within 9 hours and 41 minutes, the first exploitation attempt appeared in the wild. A complete credential theft operation followed in under 3 minutes.
How the Attack Works
Marimo deploys multiple WebSocket endpoints. The primary session WebSocket enforces authentication through a dedicated validator. But the terminal endpoint at /terminal/ws skipped that check entirely. The result was a pre authentication remote code execution vulnerability that required no credentials, no user interaction, and no special tools.
The attack chain is trivially simple:
- Attacker opens a WebSocket connection to the terminal endpoint
- Server accepts the connection and allocates a full PTY shell
- Attacker runs arbitrary commands with the privileges of the Marimo process
Sysdig's Threat Research Team observed the first real world exploitation through honeypot nodes. The attacker built a working exploit directly from the advisory description, connected to the unauthenticated endpoint, and began manually exploring the compromised environment. Within the first 12 hours, 125 IP addresses had started reconnaissance activity.
What Attackers Were After
The observed attack pattern focused on credential harvesting rather than deploying persistent malware. Attackers targeted:
- .env files containing API keys, database passwords, and cloud provider credentials
- SSH keys enabling lateral movement to other systems
- Cloud metadata endpoints leading to full account takeover
- Notebook contents containing proprietary code and intellectual property
Internet facing Marimo instances commonly share infrastructure with AI and ML platforms, LLM interfaces, and code repositories. A compromised notebook server is a launchpad into everything around it.
How Many Instances Were Exposed
Endor Labs tested 186 internet reachable Marimo instances and found that 30 of them, roughly 16%, accepted unauthenticated WebSocket handshakes. Each of those was a single request away from full shell access. The researchers deliberately stopped short of executing commands, but the successful handshake alone confirmed exploitability.
The root cause is a documentation and design problem. Marimo's documentation emphasizes remote sharing and collaborative editing, features that encourage internet accessibility. But one WebSocket route was protected while the terminal route that grants shell access was not.
What to Do Now
Marimo released version 0.23.0 on April 8 to fix the vulnerability. If you run Marimo in any capacity:
- Upgrade immediately with
pip install --upgrade "marimo>=0.23.0" - Rotate all credentials stored in .env files or accessible from the server. Assume they were compromised if the instance was internet facing.
- Never bind to 0.0.0.0 without a VPN or authenticated reverse proxy in front
- Run containers as non root with read only filesystems and minimal capabilities
- Hunt for post compromise artifacts even without observed WebSocket probes. The exploitation window was wide enough that silent access is plausible.
The Lesson for Development Teams
CVE-2026-39987 illustrates a class of vulnerability that is becoming more common as AI tooling proliferates. Interactive development environments ship with powerful features like embedded terminals and code execution engines, then get exposed to the internet through cloud deployments and collaborative workflows.
The fix for Marimo was straightforward: enforce the same authentication on the terminal WebSocket that already existed on other endpoints. The vulnerability was not a complex cryptographic failure. It was a missing check on a single route. That gap turned every exposed Marimo instance into a remote shell waiting to be opened.
If your team runs AI development tools accessible over the network, audit every endpoint. Middleware alone is not sufficient for WebSocket routes. Each endpoint needs explicit authentication enforcement.