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.
Why it matters
- Who's exposed 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.
- What it limits 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.
- Who has to decide 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.
- What doesn't add up 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.
Next story · Build · Sep 15
A query string walks past server.fs.deny on Vite dev servers left on a public portConfirmed2 publishers
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 [21].
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 [12].
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 [15]. That is one script about every two minutes [20]. Sysdig says the base64 wrap sidesteps shell-quoting problems with embedded multi-line Python [16]. 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 [11].
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 [17]. 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 [19]. 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 [13]. 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 [14]. That series began with exploitation less than 10 hours after disclosure of CVE-2026-39987 and continued with the NKAbuse RAT campaign [18].
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.
Clarity's read
What the record supports and how the coverage leans. The claims behind it follow.
Reality
- Evidence68
- Adoption66
- Hype gap+8
- Incentives72
- Confidence70
Perspective Coverage
3 publishers- Builder
- Builder 33%
- Operator
- Operator 60%
- Investor
- Investor 7%
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
The Sysdig Threat Research Team watched a single threat actor go from an open WebSocket to a live SSH session on a bastion host in eight seconds, with no agent in the loop and no sign of LLM-generated scripts or tooling.
- [2]
CVE-2026-39987 is a pre-authentication remote code execution flaw in marimo; the /terminal/ws WebSocket endpoint provides an interactive PTY shell but skips the authentication validation that other WebSocket endpoints in the same application apply correctly.
- [3]
Any client that can open a WebSocket to /terminal/ws is granted a full interactive shell running as the marimo process user with no credentials required, and exploitation requires no payload or encoding.
- [4]
The operator ran a complete credential-pivot chain end to end: initial access through the unauthenticated WebSocket terminal, an AWS Secrets Manager call using credentials harvested from the compromised instance, and SSH access to a bastion host with the retrieved private key.
- [5]
The operator used a Python toolkit they wrote and debugged by hand, in-session, over the preceding four hours.
- [6]
GitHub's advisory lists all versions up to and including marimo 0.20.4 as affected, with the fix shipped in 0.23.0, which wires the missing validate_auth() call into the terminal endpoint via PR #9098.
- [7]
The operator ignored a planted prompt injection that agent-driven operators reliably tripped, a trap every agentic threat actor Sysdig profiled against the same CVE fell into.
- [8]
Over the course of a nine-hour session the operator issued more than 850 interactive commands and used no recognizable publicly available offensive tooling.
- [9]
The first interactive command, a TCP probe across the host's /24, and the first credentialed AWS API call sit nearly four hours apart; Sysdig says that window is very likely when the operator built and debugged their tooling.
- [10]
Once the toolkit was complete and working, subsequent reconnections completed the full chain in seconds because the scripts were already on disk and only needed a single command to fire; the toolkit was pre-staged during an earlier session.
- [11]
The operator wrote and debugged a boto3 chain script over multiple sessions and dropped it as a base64-encoded Python file into /tmp/; there was no evidence suggesting the threat actor used AI during this process.
- [12]
Marimo notebooks are commonly deployed alongside ML pipelines on hosts with GPU access, large datasets and credentialed connections to AWS, GCP and various model providers, and Sysdig says a compromised marimo instance is the door to the victim's cloud account.
- [13]
"AI is lowering the barrier to entry for attackers; that much is settled."
- [14]
This is one of several operators Sysdig has profiled against CVE-2026-39987; Sysdig concludes that skilled human attackers can move at machine speed and can often better evade defenders' detections.
- [15]
The attacker iterated through eight unique scripts over a 17-minute window, each base64-decoded into /tmp/ via the pattern echo '<base64-blob>' | base64 -d > /tmp/<name>.py.
- [16]
The base64 wrap sidesteps shell-quoting issues with embedded multi-line Python.
- [17]
Every attack on marimo before this one showed fingerprints of LLM-driven operators, who typed out AWS request-signing code from memory, line by line, in a single shell session.
- [18]
Sysdig's series on CVE-2026-39987 began with exploitation less than 10 hours after disclosure and continued with the NKAbuse RAT campaign.
- [19]
More than 850 interactive commands across a nine-hour session is about 94 commands an hour, or one every 38 seconds.
- [20]
Eight scripts dropped over a 17-minute window is one script about every two minutes.
- [21]
The four-hour build-and-debug period was 1,800 times as long as the eight-second execution of the chain.
Sources
3 independent publishers whose own reporting we read for this story.
- infosecurity-magazine.comHuman Attacker Hits Machine-Speed Exploitation of Marimo RCE
1 article · September 14, 2026
- thehackernews.comHuman Attacker Exploits Marimo RCE, Reaches SSH Bastion in Eight Seconds
1 article · September 15, 2026
- webflow.sysdig.comMachine speed, hold the AI: Hand-rolled marimo CVE-2026-39987 exploit
1 article · September 10, 2026
Topics and entities
Topics
- AI-Assisted Cyberattacks
- Remote Code Execution Surfaces
- Cloud Credential Theft
- Cloud Threat Research