Sysdig Traces Marimo RCE Attacker's Eight-Second AWS-to-SSH Pivot

· Original article ↗

Summary

Sysdig TRT traced a marimo CVE-2026-39987 intrusion: an operator used a hand-built toolkit and harvested AWS credentials to retrieve an SSH key and reach a bastion in eight seconds. The report details the attack chain, detection signals and mitigations.

Key points

  • CVE-2026-39987 is a pre-authentication RCE in marimo’s /terminal/ws endpoint. Versions through 0.20.4 are affected; version 0.23.0 fixes the flaw.
  • Sysdig observed an operator use harvested AWS credentials to retrieve an SSH key from Secrets Manager and authenticate to a bastion eight seconds after opening a WebSocket session.
  • The operator built and debugged Python scripts by hand over several hours. Sysdig found no evidence of AI use during the observed activity.
  • Credentials were collected from the compromised host’s environment or files and the application’s Redis backend; the two credentials mapped to different IAM users.
  • EC2 enumeration calls were denied, but the operator’s script still attempted an SSH key push using a placeholder instance ID; AWS blocked the attempt.
  • Sysdig recommends upgrading to marimo 0.23.0 or later, restricting or disabling the terminal endpoint, auditing and limiting cloud credentials, and restricting notebook-container egress.
  • Sysdig attributed the observed WebSocket sessions to 172.236.12.17 and the callback listener to 45.79.187.72.

Article Details

Attack Vectors
  • Unauthenticated access to marimo's /terminal/ws WebSocket endpoint provided an interactive shell and enabled pre-authentication remote code execution.
  • The operator harvested AWS credentials from environment variables and credential files on the compromised host, and separately from the application's Redis backend.
  • The harvested credentials were used to query AWS Secrets Manager for an SSH private key, which was then used to authenticate to an internet-reachable bastion host.
  • The operator attempted an alternate access path using EC2 enumeration followed by an EC2 Instance Connect public-key push; the enumeration was denied and the push to a placeholder instance ID was blocked.
  • A Python reverse shell connected to an attacker-owned VPS listener over TCP port 4444.
Defensive Notes
  • Update marimo to version 0.23.0 or later; restrict or disable /terminal/ws, and require authentication at the reverse proxy if the endpoint remains enabled.
  • Audit and rotate credentials exposed on internet-reachable marimo hosts, including environment variables, credential files, application .env files, and credentials stored in the application's data layer.
  • Restrict Secrets Manager permissions so notebook-host credentials cannot retrieve unrelated secrets such as a bastion SSH key.
  • Restrict outbound network access from notebook containers, especially public-internet TCP connections on unnecessary ports.
  • Hunt for chain.py, bastion_key, and similarly named files in /tmp; monitor for the reported script-deployment patterns and sequences of Secrets Manager calls, outbound TCP connections, and SSH authentication.
  • Monitor for denied EC2 enumeration calls followed by SendSSHPublicKey attempts against the placeholder instance ID.

Indicators of compromise

TypeIndicatorContext
IPV4172[.]236[.]12[.]17Source IP for the operator's interactive WebSocket sessions; the article assesses it as disposable VPS infrastructure.
IPV445[.]79[.]187[.]72Attacker-owned VPS used as the reverse-shell callback listener and for SSH-based listener setup.

MITRE ATT&CK

T1021.004 · SSHThe operator used the retrieved private key to authenticate over SSH to an internet-reachable bastion host.T1046 · Network Service DiscoveryThe first interactive command probed the RFC1918 /24 network containing the compromised host using /dev/tcp.T1059.004 · Unix ShellThe operator used shell commands to deploy scripts, start them with nohup, and run a bash interactive shell through the reverse-shell connection.T1059.006 · PythonThe operator ran hand-written Python scripts for AWS Secrets Manager access, SSH key handling, and reverse-shell setup.T1078.004 · Cloud AccountsThe operator used harvested credentials associated with IAM users to access AWS services.T1095 · Non-Application Layer ProtocolThe operator's Python reverse shell used a raw TCP connection to the VPS listener on port 4444.T1098.004 · SSH Authorized KeysThe operator attempted to push a public key using EC2 Instance Connect's SendSSHPublicKey call; the attempt was blocked.T1190 · Exploit Public-Facing ApplicationThe operator exploited marimo's unauthenticated /terminal/ws endpoint for pre-authentication remote code execution.T1552.001 · Credentials In FilesThe operator harvested AWS credentials from credential files and application configuration on the compromised host.T1552.004 · Private KeysThe operator retrieved an SSH private key from Secrets Manager, saved it locally, and used it for bastion authentication.T1555.006 · Cloud Secrets Management StoresUsing harvested AWS credentials, the operator queried AWS Secrets Manager for a bastion SSH private key.T1571 · Non-Standard PortThe reverse-shell callback used TCP port 4444 for the listener on the attacker-owned VPS.T1580 · Cloud Infrastructure DiscoveryThe operator attempted AWS EC2 instance and key-pair enumeration with DescribeInstances and DescribeKeyPairs.

CVE

Malware

Vendors

Products

Tools

Countries

Related Articles