In 15+ years of incident response, I've watched dwell times collapse from months to days to hours. The latest reporting on a critical code execution flaw in Marimo — the increasingly popular reactive Python notebook environment — shows just how far that compression has gone: a human attacker exploited the flaw and reached an SSH bastion host in eight seconds.
Let that sink in. Not eight hours. Not eight minutes. Eight seconds from initial code execution on an exposed Marimo instance to hands on a bastion — the very system most organizations treat as their hardened gatekeeper for administrative access.
This isn't a story about a slow, methodical APT. This is a human operator moving at machine speed because the path from an internet-facing notebook environment to internal infrastructure was short, unmonitored, and unauthenticated. If you run Marimo, Jupyter, or any notebook platform exposed to a network segment that can reach administrative infrastructure, you need to treat this as an active threat — today.
What Happened
Marimo (from marimo-team) is an open-source, reactive Python notebook that has gained rapid adoption in data science and engineering teams as a modern alternative to Jupyter. Like all notebook platforms, Marimo's core design assumption is that the user at the keyboard is trusted — notebooks execute arbitrary Python code by definition. When that execution surface is exposed without proper authentication and network isolation, the notebook itself becomes the exploit: no memory corruption required, no exotic payload, just a web-request-driven path to os.system().
According to the reporting, an attacker leveraged the critical code execution condition in Marimo and, within eight seconds, had pivoted to an SSH bastion host. The speed of that pivot tells us several things as defenders:
- The Marimo instance had direct network reachability to administrative infrastructure. There was no segmentation between the notebook workload and the bastion's management plane.
- Credentials or SSH keys were likely accessible from the notebook context — either on disk, in environment variables, or via an agent — enabling an immediate, non-interactive hop.
- The attacker came prepared. An eight-second pivot means the commands were staged and executed almost mechanically. This was not exploration; it was a rehearsed playbook.
No CVE identifier has been published in the reporting for this issue, and I won't speculate on one. What matters operationally is the class of vulnerability: unauthenticated or insufficiently protected remote code execution on a notebook server, combined with a flat network path to crown-jewel access infrastructure.
Technical Analysis: The Attack Chain
From a defender's perspective, the kill chain breaks down like this:
Stage 1 — Initial Access (T1190: Exploit Public-Facing Application). The attacker identifies an internet-facing or internally reachable Marimo instance. Default Marimo deployments bind to a port (commonly 2718) and, critically, the security posture depends entirely on how the operator launched it. Instances started with permissive flags (e.g., --headless without token/password protection, or exposed edit mode) effectively hand arbitrary Python execution to anyone who can reach the port.
Stage 2 — Execution (T1059.006: Python). Through the notebook interface or the underlying execution flaw, the attacker runs Python code in the context of the Marimo server process. Observable artifacts: the marimo process spawning child processes such as bash, sh, curl, wget, id, whoami, or network enumeration tools.
Stage 3 — Lateral Movement (T1021.004: SSH). Within seconds, the attacker initiates an outbound SSH connection from the compromised host to the bastion. This is the loudest, most detectable moment in the chain: a data-science workload host making an interactive SSH connection to administrative infrastructure is almost never legitimate.
Stage 4 — Establish Foothold. Once on the bastion, the attacker is positioned on the management plane — the one system with reachability to everything.
Exploitation Status
The reporting describes confirmed human exploitation with an observed end-to-end compromise — this is not theoretical. The eight-second pivot was observed in a real attack. Treat any reachable Marimo instance as potentially hostile territory until verified otherwise.
Detection & Response
The detection opportunities here are strong because the attack chain crosses three well-instrumented boundaries: process execution from the notebook server, outbound SSH from a workload host, and authentication on the bastion itself.
Sigma Rules
The highest-fidelity signal in this entire chain is the Marimo process spawning a shell or network utility — there is essentially no legitimate reason for it in production. The second rule catches the lateral movement: SSH client execution originating from a notebook/service context.
---
title: Marimo Notebook Server Spawning Shell or Command Interpreter
id: 3f8c1a92-7b4e-4d51-a6c9-2e8f5b1d9034
status: experimental
description: Detects the Marimo Python notebook server process spawning shells, SSH clients, or download utilities, consistent with exploitation of an exposed Marimo instance leading to interactive code execution.
references:
- https://www.infosecurity-magazine.com/news/human-attacker-machine-speed/
- https://attack.mitre.org/techniques/T1059/006/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.execution
- attack.t1059.006
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentCommandLine|contains: 'marimo'
selection_child_img:
Image|endswith:
- '/bash'
- '/sh'
- '/dash'
- '/zsh'
- '/python'
- '/python3'
selection_child_net:
Image|endswith:
- '/curl'
- '/wget'
- '/ssh'
- '/nc'
- '/ncat'
- '/socat'
condition: selection_parent and 1 of selection_child_*
falsepositives:
- Notebook users legitimately invoking shell commands via subprocess in development environments
level: high
---
title: SSH Client Execution From Notebook or Service Process Context
id: 91d4e7b6-2c5a-4f38-b17d-6a9c3e4f2081
status: experimental
description: Detects SSH client connections initiated by a Python or notebook-related parent process, indicating lateral movement from a compromised notebook server toward SSH bastions or internal hosts.
references:
- https://www.infosecurity-magazine.com/news/human-attacker-machine-speed/
- https://attack.mitre.org/techniques/T1021/004/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.lateral_movement
- attack.t1021.004
logsource:
category: process_creation
product: linux
detection:
selection_img:
Image|endswith: '/ssh'
selection_parent:
ParentImage|endswith:
- '/python'
- '/python3'
- '/marimo'
- '/jupyter'
- '/node'
condition: selection_img and selection_parent
falsepositives:
- Automated deployment or data pipeline scripts using Paramiko/subprocess SSH from Python (tune by service account and destination)
level: high
KQL — Microsoft Sentinel / Defender
This query hunts the exact pivot observed in the attack: a Python/notebook process context launching an SSH client. It assumes Linux Syslog or Defender for Endpoint process telemetry is flowing into Sentinel. Run it across all notebook, data-science, and analytics workload hosts.
let lookback = 7d;
let notebookParents = dynamic(["marimo", "jupyter", "python", "python3", "ipython"]);
union isfuzzy=true
(DeviceProcessEvents
| where TimeGenerated > ago(lookback)
| where FileName in~ ("ssh", "scp", "sftp")
| where InitiatingProcessFileName has_any (notebookParents)
or InitiatingProcessCommandLine has_any (notebookParents)
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine,
InitiatingProcessFileName, InitiatingProcessCommandLine, AccountName),
(Syslog
| where TimeGenerated > ago(lookback)
| where ProcessName =~ "sshd"
| where SyslogMessage has "Accepted"
| extend SourceIP = extract(@"from ([0-9\.]+)", 1, SyslogMessage)
| project TimeGenerated, Computer, SyslogMessage, SourceIP)
| sort by TimeGenerated desc
The Syslog half of that union surfaces successful SSH authentications on your bastions — correlate accepted logins with source IPs that belong to notebook/workload hosts rather than expected admin jump stations. An Accepted from a data-science VM to your bastion is a five-alarm event.
Velociraptor VQL
Use this hunt artifact to sweep your Linux fleet for notebook server processes that have spawned shells or network tooling — fast triage before you even know whether you have an exposure.
-- Hunt for Marimo/notebook server processes spawning shells or network utilities
SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE CommandLine =~ '(?i)marimo|jupyter'
OR (
Name =~ '(?i)^(bash|sh|dash|ssh|scp|curl|wget|nc|ncat|socat)$'
AND Ppid IN (
SELECT Pid FROM pslist()
WHERE CommandLine =~ '(?i)marimo|jupyter|python.*notebook'
)
)
Pair this with a netstat() check for listening services on common notebook ports to find exposed instances before an attacker does:
-- Find listening notebook services across the fleet
SELECT Pid, Name, Path, Address, Port, State, Status
FROM netstat()
WHERE State =~ 'LISTEN'
AND Port IN (2718, 8888, 8080, 8889)
AND (Name =~ '(?i)marimo|python|jupyter' OR CommandLine =~ '(?i)marimo|jupyter')
Remediation: Harden Marimo Before the Next Eight Seconds
1. Inventory and Contain (Do This First)
- Sweep your environment for running Marimo instances:
ps aux | grep marimoon Linux hosts, and scan for listeners on port 2718 (and common notebook ports) across your network. - If you find an internet-facing or unauthenticated instance, take it offline immediately and treat the host as potentially compromised. Check for child shells, outbound SSH, and new authorized_keys entries before returning it to service.
2. Upgrade and Configure Authentication
- Upgrade to the latest Marimo release from the official repository (
pip install -U marimo); the maintainers ship security fixes rapidly and you should be on the most current build. - Never run Marimo in an exposed edit mode without authentication. When launching headless or on a shared host, bind to localhost and place it behind an authenticated reverse proxy:
# Bind Marimo to localhost only — never expose directly to the network
marimo run notebook.py --host 127.0.0.1 --port 2718
# Verify nothing is listening on external interfaces
ss -tlnp | grep -E '2718|8888'
# Quick exposure sweep across a subnet (run from your scanner, adjust range)
nmap -p 2718,8888 --open 10.0.0.0/24 -oG - | grep open
# Restrict egress from notebook hosts: block outbound SSH to bastion segments
sudo iptables -A OUTPUT -p tcp --dport 22 -d 10.10.0.0/24 -m owner ! --uid-owner deploysvc -j REJECT
3. Segment the Network — This Is the Real Fix
The eight-second pivot was only possible because the notebook host could reach the bastion. That is an architecture failure, not just a software flaw:
- Place notebook/analytics workloads in an isolated VLAN or security group with no route to management plane subnets.
- Enforce a default-deny egress policy on workload hosts; data-science boxes almost never need outbound TCP/22.
- Require all administrative SSH to originate from a hardened PAW or jump host — and alert on any bastion authentication from outside that source set.
4. Protect Credentials on Workload Hosts
- Audit notebook hosts for stored SSH private keys (
~/.ssh/,/home/*/.ssh/), cloud metadata credentials, and environment-variable secrets. - Where SSH from a workload is genuinely required (e.g., pipelines), use short-lived certificates (e.g., an SSH CA) scoped to specific service accounts and destinations — never static keys sitting on disk.
5. Detection-as-Code
Deploy the Sigma rules and KQL queries above to your SIEM today. The Marimo-spawns-shell rule is the single highest-value detection from this story: it's specific, low-noise in production, and fires at the earliest moment of the kill chain — before the eight-second clock starts.
The Bottom Line
Attackers — human ones — are now executing full pivots faster than most SOAR playbooks finish enriching an alert. If your detection strategy assumes you'll catch intrusions during a leisurely post-exploitation phase, this incident is your wake-up call. The defensive battle is won or lost at three points: whether the notebook is exposed, whether it's segmented from the bastion, and whether you're watching for a notebook process spawning a shell. Close all three gaps this week.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.