Security1 publisher2 min readPublished
A hand-debugged Python toolkit turned marimo CVE-2026-39987 into bastion SSH in eight seconds
Sysdig's threat research team watched one operator work a marimo notebook host for nine hours with hand-written scripts, and the eight-second jump to a bastion host at the end ran on tooling already staged on disk.
The Watch · Security desk

What happened
- Sysdig's threat research team watched one operator move from an open WebSocket to a live SSH session on a bastion host in eight seconds, with no agent in the loop and no LLM-generated scripts or tooling.
- The flaw is CVE-2026-39987, a pre-authentication RCE in marimo: the /terminal/ws endpoint hands out an interactive PTY shell while skipping the authentication check the application's other WebSocket endpoints apply.
- The chain ran in three steps: unauthenticated shell as the marimo process user, an AWS Secrets Manager call with credentials harvested from the instance, then SSH to a bastion host with the retrieved private key.
- GitHub's advisory lists every marimo version up to and including 0.20.4 as affected, and 0.23.0 wires the missing validate_auth() call into the terminal endpoint via PR #9098.
- The operator walked past a planted prompt injection that every agentic threat actor Sysdig has profiled against this same CVE tripped.
Compiled by The WatchSomething wrong?How this is made
Why it matters
- exposure Anyone running marimo next to an ML pipeline should treat the notebook host's instance role as the attacker's first credential and scope the blast radius to everything that role can read in Secrets Manager.
- constraint Detection tuned to windows measured in minutes will only ever see this chain after it completes, so the alerting decision moves to the shell open and the script drops, not the credential pivot.
- decision Exploit complexity offers no help in scheduling the upgrade here: an unauthenticated WebSocket needs no payload, so who can reach the port decides who is exposed.
- contradiction Sysdig calls the AI-lowers-the-bar question settled while presenting a human operator who outran and out-evaded the agents it profiled, and the post supplies no speed figures for those agents to compare against.
The eight seconds were a replay of work already finished. Sysdig's timeline puts the first interactive command, a TCP probe across the host's /24, and the first credentialed AWS API call nearly four hours apart, and Sysdig says that window is very likely when the operator built and debugged the tooling [9]. By the reconnection the scripts sat on disk, and the chain needed one command to fire [10]. Four hours of build against eight seconds of execution: preparation ran 1,800 times longer than the run [3].
Marimo notebooks tend to be deployed alongside ML pipelines, on hosts with GPU access, large datasets and credentialed connections to AWS, GCP and model providers, which is why Sysdig calls a compromised instance the door to the victim's cloud account [15].
Delivery was unremarkable. Each script arrived as `echo '<base64-blob>' | base64 -d > /tmp/<name>.py`, and eight unique ones went in over a 17-minute window [11]. That is one script about every two minutes [2]. Sysdig says the base64 wrap sidesteps shell-quoting problems with embedded multi-line Python [12]. The boto3 chain script had been written and debugged across multiple sessions before it was dropped, and Sysdig reports no evidence of AI use in that process [13].
Every earlier marimo intrusion Sysdig profiled looked different. Those operators typed AWS request-signing code out from memory, line by line, in a single shell session [14]. This operator ran more than 850 interactive commands across the nine-hour session and used no recognisable publicly available offensive tooling [8]. That works out at about 94 commands an hour, one every 38 seconds, sustained for nine hours on a notebook host [1]. The eight-second pivot gives a detection engine almost nothing to match on. The four hours that produced it were 850 commands of shell noise.
The post opens with a claim its case study does not test. "AI is lowering the barrier to entry for attackers; that much is settled," the Sysdig Threat Research Team wrote [16]. The evidence here is one operator in one vendor's telemetry, and the comparison set is Sysdig's own profiles of agentic actors against the same CVE, whose speeds the post does not quantify [18]. That series began with exploitation less than 10 hours after disclosure of CVE-2026-39987 and continued with the NKAbuse RAT campaign [17].
What to watch
- A second victim showing the same echo-base64-into-/tmp/ delivery pattern, which would extend this from one session to a campaign.
- Scan counts for internet-reachable marimo instances still serving /terminal/ws on 0.20.4 or earlier.
- The same pre-staged toolkit appearing in another operator's hands, a sign it is being shared or sold.