Machine speed, hold the AI: Hand-rolled marimo CVE-2026-39987 exploit

Machine speed, hold the AI: Hand-rolled marimo CVE-2026-39987 exploit
Sysdig TRT observed a skilled threat actor exploit CVE-2026-39987 in marimo to move from an unauthenticated WebSocket terminal to SSH access on a bastion host in eight seconds, using hand-built Python tooling rather than LLM-generated scripts. The campaign involved AWS credential harvesting, Secrets Manager access, EC2 enumeration, and direct SSH pivoting, with infrastructure tied to Akamai Connected Cloud/Linode. #CVE-2026-39987 #marimo #AWSSecretsManager #Linode

Keypoints

  • The attacker exploited CVE-2026-39987, a pre-authentication RCE flaw in marimo’s /terminal/ws WebSocket endpoint.
  • Sysdig TRT saw the operator go from WebSocket access to SSH on a bastion host in eight seconds.
  • The threat actor used hand-written Python scripts, not recognizable offensive tooling or LLM-generated automation.
  • The operator harvested AWS credentials from two different sources and validated them before using them in the attack chain.
  • One script retrieved a secret from AWS Secrets Manager and wrote a private SSH key to /tmp/bastion_key for reuse.
  • A separate EC2 Instance Connect attempt failed after denied enumeration calls, then incorrectly tried SendSSHPublicKey against a null instance ID.
  • The attacker used VPS infrastructure in AS63949 Akamai Connected Cloud/Linode for both source activity and callback services.

MITRE Techniques

  • [T1190 ] Exploit Public-Facing Application – The attacker gained initial access by abusing marimo’s unauthenticated terminal WebSocket endpoint. [‘exploited CVE-2026-39987, a pre-authentication remote code execution (RCE) vulnerability in marimo’ and ‘Any client that can open a WebSocket to that path is granted a full interactive shell’]
  • [T1059.006 ] Command and Scripting Interpreter: Python – The operator wrote and ran custom Python scripts for AWS access, key handling, and pivoting. [‘they wrote a Python toolkit they wrote and debugged by hand’ and ‘boto3 chain script’]
  • [T1003 ] OS Credential Dumping – The attacker harvested AWS credentials from the compromised host’s environment and Redis-backed application data. [‘Credential 1 was harvested from environment variables and credential files’ and ‘Credential 2 was returned by the application’s Redis backend’]
  • [T1528 ] Steal Application Access Token – The operator reused harvested cloud credentials to access AWS Secrets Manager and pivot further into the environment. [‘using credentials harvested from the compromised instance’ and ‘replayed against the internet-reachable bastion host’]
  • [T1552.001 ] Unsecured Credentials: Credentials In Files – Credentials and the resulting SSH key were handled from files on disk such as /tmp/bastion_key. [‘wrote the retrieved key to /tmp/bastion_key’ and ‘Hunt for chain.py, bastion_key’]
  • [T1082 ] System Information Discovery – The attacker enumerated EC2 resources to identify targets and determine instance IDs. [‘DescribeInstances’, ‘DescribeKeyPairs’, ‘DescribeInstanceInformation’ and ‘enumerate running instances to get an instance ID’]
  • [T1021.004 ] Remote Services: SSH – The operator authenticated to a bastion host over SSH using the retrieved private key. [‘SSH access to a bastion host with the retrieved private key’ and ‘SSH authentication observed at the bastion host’]
  • [T1105 ] Ingress Tool Transfer – The attacker dropped base64-encoded Python tooling into /tmp/ for later execution. [‘echo ” | base64 -d > /tmp/.py’ and ‘the toolkit is reproduced below, in deployment order’]
  • [T1041 ] Exfiltration Over C2 Channel – The operator set up a reverse-shell listener and callback infrastructure on an attacker-owned VPS. [‘starts a new nohup nc -lvp 4444 listener’ and ‘callback sink’]
  • [T1578 ] Modify Cloud Compute Infrastructure – The EC2 Instance Connect path attempted to push an SSH public key directly to a target instance. [‘ec2:SendSSHPublicKey fired’ and ‘use EC2 Instance Connect to push an operator-controlled public key’]

Indicators of Compromise

  • [IP address ] Source WebSocket session origin and attacker VPS callback host – 172.236.12.17, 45.79.187.72
  • [AWS API calls ] CloudTrail and session activity tied to the intrusion – secretsmanager:GetSecretValue, ec2:SendSSHPublicKey
  • [File paths ] Dropped tooling and recovered key material on the compromised host – /tmp/chain.py, /tmp/bastion_key
  • [File paths ] Additional execution/log artifacts from the toolkit – /tmp/full_chain.py, /tmp/chain.log
  • [Process/artifact names ] Base64-decoded Python chain scripts and shell outputs – /tmp/callback.log, /tmp/chain_output.txt
  • [Filename/command artifact ] Reverse-shell and listener tooling – nc -lvp 4444, nohup python3 /tmp/chain.py


Read more: https://www.sysdig.com/blog/machine-speed-hold-the-ai-hand-rolled-marimo-cve-2026-39987-exploit