Autopsy 10 · Post-compromise lateral movement | Comic Strip 11 · Four Pivots

Would Ethosure have caught this?  Sysdig’s LLM-driven post-exploitation in four pivots

An attacker exploited a Marimo notebook, then handed the reins to an LLM agent that pivoted four times — from notebook to cloud credentials to AWS Secrets Manager to an internal PostgreSQL database — in under one hour. The bastion phase alone ran in under two minutes. Signature-based detection tuned for scripted attackers is the wrong instrument for an agentic adversary.

Series: Would Ethosure have caught this?
Root cause: Signature-shaped detection versus agent-shaped adversary
Coding-ethos policy: runtime.behaviour.bulk_export_rate_gate

The incident

Marimo pre-authentication remote code execution was disclosed on April 8, 2026 as CVE-2026-39987 at CVSS 9.3. The vulnerable /terminal/ws WebSocket endpoint provided an interactive PTY-backed shell but omitted the validate_auth() call used by the application’s other WebSocket endpoints. First observed exploitation in the wild occurred nine hours and forty-one minutes after the advisory was published — before any public proof-of-concept existed. On May 10, 2026 Sysdig’s Threat Research Team captured a full intrusion. From an origin at 157.66.54.26 (AS141892, Indonesia), an attacker compromised an internet-reachable Marimo host and then let an LLM agent execute the post-compromise sequence: harvest two cloud credentials, replay them through a Cloudflare Workers egress pool, retrieve an SSH private key from AWS Secrets Manager, and use eight parallel SSH sessions against an internal bastion to dump a full PostgreSQL database. End-to-end: under one hour. Bastion phase: under two minutes.

The applicable coding-ethos policy

Policy packRegulated-enterprise base pack (with model / provider governance overlay)
Principledetection-tempo-parity
Control familyPost-compromise behavioural detection + Secrets Manager access gate

Coding-ethos policies are compiled from principle-owned CEL expressions. Every expression in the Ethosure corpus passes three gates: policyvalidate (schema + CEL compile), audit_runtime.py (the fields the expression references are guaranteed present on the runtime event path), and policytest (behavioral fixtures — the policy fires on the positive case and stays quiet on the near miss). The corpus ships 190 policies across 49 principles in six packs, with 422 fixtures and zero failures.

READ  Would Ethosure have caught this? The code freeze that wasn't

Walkthrough

  1. The novelty is not the vulnerability. Marimo’s missing auth check is a classic bug and the CISA KEV listing is proof. The novelty is the tempo. Four pivots in under an hour. A full database dumped in under two minutes. Any detection tuned to a script-kiddie cadence loses that race by design.
  2. runtime.behaviour.bulk_export_rate_gate fires on any egress event whose payload size or row count exceeds a per-workload threshold in a rolling window measured in seconds rather than minutes. It returns severity block. The Sysdig bastion phase ran in under 120 seconds; a minute-scale window would never have caught it. The policy makes the window seconds-scale and pushes the threshold down to a value the workload owner has to approve.
  3. secrets.retrieval.workload_binding_required targets the AWS Secrets Manager step. A notebook host has no legitimate reason to retrieve an SSH bastion key. The expression fires on any Secrets Manager GetSecretValue call whose caller workload does not match the secret’s declared consumer list. Attach the consumer list at secret creation time and the pivot dies at the credential boundary.
  4. runtime.identity.marimo_no_outbound_ssh is the third expression. It is deliberately narrow. Marimo runtimes exist to serve reactive notebooks; they do not originate SSH sessions. The expression fires on any process in a Marimo-labelled runtime whose network profile includes an outbound port-22 connection. Eight parallel SSH sessions were never legitimate.

Policy YAML

# Pack: regulated-enterprise-base (v2)
# Overlay: model-provider-governance
principles:
  - id: detection-tempo-parity
    title: Detection Tempo Parity
    directive: >-
      Detection windows and thresholds must be sized for agentic adversaries operating
      at second-scale, not for scripted attackers operating at minute-scale.
    policy:
      expressions:
        - id: runtime.behaviour.bulk_export_rate_gate
          scope: agent_action
          severity: block
          event: PreToolUse
          principle_ids:
            - detection-tempo-parity
            - security-by-design
          skill_id: post-compromise-hardening
          when: >
            tool_call.category in ["data_export", "http_request", "db_query"]
            && export.window_seconds <= 120
            && (export.rows > workload.export_rate_threshold.rows
                || export.bytes > workload.export_rate_threshold.bytes)
          message: >-
            Export rate exceeds the workload's approved second-scale threshold.
          advice: >-
            Reject the export. Raise the threshold only through a signed change entry recorded
            in the evidence layer. The Sysdig bastion phase moved an entire database in under
            two minutes; the detection window must be smaller than the attack window.

        - id: secrets.retrieval.workload_binding_required
          scope: agent_action
          severity: block
          event: PreToolUse
          principle_ids:
            - detection-tempo-parity
            - least-authority-in-the-pipeline
          when: >
            tool_call.category == "secrets_manager_get"
            && !secret.declared_consumers.exists(c,
                 c.workload_id == runtime.workload_id)
          message: >-
            Secrets Manager retrieval from a workload that is not on the secret's declared
            consumer list.
          advice: >-
            Add the workload to the consumer list with a signed change entry, or reject the
            call. Notebook hosts should never appear on a bastion-key consumer list.

        - id: runtime.identity.marimo_no_outbound_ssh
          scope: agent_action
          severity: block
          event: PreToolUse
          principle_ids:
            - detection-tempo-parity
            - security-by-design
          when: >
            runtime.labels.exists(l, l == "marimo")
            && tool_call.category == "network_connect"
            && tool_call.destination.port == 22
          message: >-
            Marimo runtime is attempting an outbound SSH connection.
          advice: >-
            Reject the connection. If the workload genuinely requires SSH egress, remove the
            marimo label and re-declare the runtime kind; the label carries the assumption that
            SSH is not part of the workload's normal behaviour.

Assurance boundary. Fixtures prove that synthetic positive cases fire and near-misses stay quiet. They do not establish production alert rates. DLP-backed controls depend on upstream detection, shell-command regexes are defense in depth rather than a sandbox boundary, and regulatory tags are engineering aids requiring counsel review.

READ  Would Ethosure have caught this? The Nx s1ngularity attack that weaponised developers’ own AI CLIs

Where this policy lives in the corpus

The Ethosure importable corpus ships six coding-ethos packs. Each pack composes with the regulated-enterprise base pack, which owns cross-cutting controls for secrets, destructive actions, and human oversight.

  • Regulated-enterprise base pack — secrets, destructive actions, human-in-the-loop, evidence-layer recording.
  • Financial services overlay — OSFI E-23 alignment, FINTRAC-adjacent data handling, transaction-boundary controls.
  • Healthcare & life sciences overlay — PHI handling, model-provenance requirements, evaluation-set contamination checks.
  • Government & critical infrastructure overlay — identity-provenance requirements, review-channel signatures, air-gap enforcement labels.
  • Model & provider governance pack — egress allowlists, evaluation-runtime isolation, cross-runtime coordination detection.
  • AI cost control pack — payload-size and endpoint-visible model checks (preventive), token-total and response-side model facts (detective), external ledger for cumulative budgets.

Published September 3, 2026 · Ethosure · Part of the Autopsy Series.

Subscribe to Ethosure's Newsletter to get monthly updates on AI Governance

We don’t spam! Read our privacy policy for more info.