CVE-2026-39987
Published April 2026 | Category: Cybersecurity
Quick Answer
CVE-2026-39987 is a critical pre-authentication remote code execution vulnerability in Marimo, the open-source reactive Python notebook used for AI, machine learning, and data science workflows. It carries a CVSS v4.0 score of 9.3, affects all Marimo versions through 0.20.4, and was first exploited in the wild approximately 9 hours and 41 minutes after public disclosure on April 8, 2026 — with full credential theft completed in under 3 minutes once an attacker gained shell access. The vulnerability exists in the /terminal/ws WebSocket endpoint, which accepted unauthenticated connections and granted a full PTY (pseudo-terminal) shell without ever calling validate_auth(). Other WebSocket endpoints on the same Marimo server (/ws) correctly enforced authentication. The fix shipped in Marimo version 0.23.0. Every organization that ran an internet-reachable Marimo instance prior to April 8, 2026 should treat that deployment as potentially compromised, rotate every credential it had access to, and begin formal incident response.
This is not a routine CVE. Three things make CVE-2026-39987 worth a dedicated, in-depth analysis instead of a patch advisory.
Table of Contents
First, the exploitation window. Sysdig’s Threat Research Team — which deployed honeypot nodes running vulnerable Marimo instances across multiple cloud providers specifically to observe in-the-wild exploitation — measured the time from advisory publication to first successful exploitation at 9 hours and 41 minutes. No public proof-of-concept code existed at that point. The attacker built a working exploit directly from the human-readable advisory description, connected to the unauthenticated terminal endpoint, and began running commands. For comparison, the previous notable AI-toolchain incident — CVE-2026-33017 in Langflow — was exploited within twenty hours. CVE-2026-39987 cut that window in half, and it did so against a tool with one-tenth the user base of the larger orchestration platforms. The conclusion is unavoidable: attackers are now monitoring every advisory feed, on every project, regardless of size.
Second, the blast radius. Marimo is not a customer-facing application. It is part of the AI/ML development toolchain, which means the credentials and data accessible from a compromised Marimo instance are typically several orders of magnitude more sensitive than the credentials accessible from a typical web server compromise. Access to a Marimo host frequently means access to LLM provider API keys, cloud credentials in nearby .env files, training datasets, model artifacts, fine-tuning pipelines, internal data warehouses, and source code repositories. The Cloud Security Alliance’s research note on the incident is unusually clear about this: a successful exploitation functions less like a server compromise and more like a credential harvesting operation against the entire AI development environment.
Third, the lesson generalizes. The bug itself is a single missing function call — validate_auth() was not invoked on one specific WebSocket route while it was correctly invoked on every other route on the same server. That kind of asymmetric trust failure is the most common shape of vulnerability in modern web applications, and the underlying pattern (an inconsistent authentication check across endpoints that share a server) is present in dozens of widely deployed AI/ML tools whose security maturity is still catching up to their adoption velocity. Marimo is the first major incident in this class. It will not be the last.
This four-part analysis is published for the security teams and AI engineering leaders who are reading this in the middle of an incident response, and for the much larger group of teams who are not yet reading it because they do not know they are exposed. We have written it to be useful to both audiences without compromising on technical accuracy for either.
Independence and Methodology Disclosure
Axis Intelligence has no commercial relationship with Marimo, Sysdig, Endor Labs, the Cloud Security Alliance, or any other vendor mentioned in this analysis. We have not received early access, sponsored briefings, or compensation from any party tied to this story. Nothing in this report is sponsored or affiliate-driven.
This analysis draws on primary sources: the Marimo project’s GitHub security advisory, the Marimo release notes for version 0.23.0, the Sysdig Threat Research Team report on in-the-wild exploitation, the Endor Labs technical write-up, the Cloud Security Alliance research note on AI toolchain implications, SecurityWeek’s reporting, The Hacker News coverage, and the canonical NIST National Vulnerability Database entry for CVE-2026-39987. Defender framework references draw on the OWASP Top 10 for 2021, the OWASP API Security Top 10, the NIST Cybersecurity Framework 2.0, and the CISA Known Exploited Vulnerabilities catalog.
What Marimo Is and Why This Matters
Simple: Marimo is a free, open-source tool that lets data scientists and AI engineers write Python code in a notebook (a document with code blocks and outputs mixed together) and run it. It is similar to Jupyter, the most widely used Python notebook tool, but with a different design that updates the entire notebook automatically when any code changes. People run Marimo on their laptops, on shared servers, and inside containers in the cloud. The bug we are discussing let anyone on the network reach a Marimo server and immediately get a command line on the machine, without needing a password or any other credential.
Technical: Marimo is a reactive notebook framework for Python, distributed via PyPI and developed by the marimo-team organization on GitHub with approximately 19.6 thousand stars at the time of disclosure. Its differentiator from Jupyter is a dataflow-based execution model: when a cell changes, every dependent cell re-runs automatically, ensuring that code, outputs, and program state remain consistent. This is operationally significant for AI/ML work because it eliminates the most common reproducibility failure mode of Jupyter notebooks (stale state). Marimo is commonly deployed in three modes: locally for individual development, on shared internal servers for team collaboration, and in containers as part of CI/CD or production inference pipelines. The default port is 2718. The integrated terminal feature, which was the entry point for this CVE, is available in Marimo’s edit mode and is intended to give notebook users a shell on the same host for ad-hoc operations.
Analogy: Imagine a shared lab notebook in a research office, the kind a chemist or biologist might keep on a desk. Anyone with the door key can read it, edit it, and run experiments described in it. Marimo is the digital equivalent for AI engineers. The bug we are discussing is the lock on the door working perfectly for the front entrance but missing entirely from the side door — and the side door opens directly onto a workbench full of poison cabinets.
CVE-2026-39987 Quick Facts
| Item | Detail |
|---|---|
| CVE ID | CVE-2026-39987 |
| Vulnerability class | Pre-authentication remote code execution (RCE) |
| CVSS v4.0 base score | 9.3 — Critical |
| CWE class | CWE-306 (Missing Authentication for Critical Function), CWE-78 (OS Command Injection downstream) |
| Affected component | Marimo terminal WebSocket endpoint (/terminal/ws) |
| Affected versions | All versions through 0.20.4 (note: Endor Labs flagged the initial OSV entry as understated) |
| Fixed in version | 0.23.0 |
| Public disclosure date | April 8, 2026 |
| First exploitation in the wild | April 8, 2026, ~9 hours 41 minutes after disclosure |
| Time to credential theft | < 3 minutes after shell access |
| Public PoC at exploitation time | None — attacker built from advisory text |
| Default Marimo port | 2718 (also frequently fronted on 80/443/8080/8443 via reverse proxy) |
| Reporter / honeypot detector | Sysdig Threat Research Team |
| Project repository | github.com/marimo-team/marimo |
| Project size | ~19.6k GitHub stars |
| Authentication required for exploitation | None |
| Network access required | TCP reachability to Marimo HTTP server |
| User interaction required | None |
| Patch availability | Available immediately on disclosure |
The Technical Anatomy of CVE-2026-39987
The bug is small. That is the most important thing to understand about it. Pre-authentication remote code execution vulnerabilities in production software are usually the result of a single missing safety check, and CVE-2026-39987 is exactly that. It is worth walking through the bug carefully because the structure is more instructive than the count.
Marimo’s HTTP server exposes several WebSocket endpoints. WebSockets are a long-lived bidirectional connection protocol used for real-time features in modern web applications. Marimo uses them for several purposes — synchronizing notebook state between the browser and the server, streaming code execution output, and (relevant here) providing an integrated terminal that lets the notebook user run shell commands directly from the browser interface.
The terminal WebSocket endpoint is /terminal/ws. When a client connects to it, the server is supposed to verify that the client is authenticated before granting shell access. In Marimo’s architecture, that verification happens through a function called validate_auth(), which checks the session token or access token associated with the connection. Other WebSocket endpoints on the same server — for example /ws, the main notebook synchronization endpoint — correctly call validate_auth() before accepting traffic.
The terminal endpoint did not.
The Marimo project advisory states the issue plainly: “Unlike other WebSocket endpoints (e.g., /ws) that correctly call validate_auth() for authentication, the /terminal/ws endpoint only checks the running mode and platform support before accepting connections, completely skipping authentication verification.”
The “running mode and platform support” check confirms two things: that the server is in edit mode (where the terminal feature is enabled) and that the host operating system supports the PTY allocation that the terminal needs. Both of these are environmental checks. Neither of them establishes whether the connecting client has any right to use the terminal. An attacker who can reach the Marimo HTTP port and complete a WebSocket handshake to /terminal/ws is granted a full interactive shell as the user running the Marimo process.
The exploit path requires no credentials, no user interaction, no exotic protocol manipulation, and no public proof-of-concept code. The advisory description itself is sufficient to reproduce it. An attacker reading the advisory already knows everything they need to know.
Why “Pre-Authentication” Is the Phrase That Matters
In vulnerability triage, the single most important distinction is between authenticated and unauthenticated vulnerabilities. An authenticated vulnerability requires the attacker to already have valid credentials before they can exploit it. An unauthenticated — or “pre-auth” — vulnerability does not. The blast radius of an unauthenticated bug is the entire population of network-reachable instances. The blast radius of an authenticated bug is limited to whatever credentials the attacker has already obtained.
CVE-2026-39987 is the worst kind: pre-authentication, requiring no user interaction, exposed via a standard protocol, on a common port, in software with substantial enterprise adoption. It is the vulnerability shape that gets weaponized fastest, scanned for most aggressively, and ingested into automated exploitation toolchains within hours.
The CVSS v4.0 score of 9.3 reflects that combination. CVSS is not a perfect measure, but at the high end of the scale it does a reasonable job of conveying urgency. A 9.3 score on a pre-auth RCE in widely deployed software means: this is a top-priority patch, deploy it before the end of the day, and treat any internet-reachable instance as potentially already compromised.
The Exploitation Timeline
The Sysdig Threat Research Team’s measurement of the exploitation timeline is the most operationally important data point in the entire incident, and it deserves to be reproduced in detail rather than summarized.
Hour 0 (April 8, 2026, advisory publication). The Marimo project publishes the security advisory describing the vulnerability, including the technical details of the missing authentication check on the /terminal/ws endpoint. Version 0.23.0 ships simultaneously, containing the fix.
Hour 0 to Hour 9. Sysdig honeypot nodes — vulnerable Marimo instances deployed across multiple cloud providers specifically to observe in-the-wild exploitation activity — receive routine internet background traffic. No exploit attempts.
Hour 9 hours 41 minutes. First exploitation attempt against a Sysdig honeypot. The attacker connects to /terminal/ws, completes the WebSocket handshake without supplying credentials, and is granted a PTY shell. According to the Sysdig report, there was no public PoC at this time. The attacker had built a working exploit directly from the advisory description.
Hour 9 hours 41 minutes + ~30 seconds. The attacker begins manually exploring the compromised environment. They read the contents of every file in the working directory.
Hour 9 hours 41 minutes + ~1 minute. The attacker searches for SSH keys in standard locations.
Hour 9 hours 41 minutes + ~3 minutes. Complete credential theft operation finished. The attacker has, at this point, harvested whatever cloud credentials, API keys, and SSH keys were accessible from the Marimo process’s filesystem context.
That is the entire timeline from disclosure to first credential exfiltration: just under ten hours from public advisory to complete credential theft, on a tool that maintains roughly twenty thousand GitHub stars — meaning it is widely used but is not in the top tier of AI/ML platforms by adoption. The attackers were not waiting for a juicy target. They were monitoring advisory feeds across the entire AI/ML ecosystem and weaponizing whatever appeared.
The Sysdig observation also implicitly establishes something important about attacker capability: building a working exploit from the advisory description, with no public PoC, in under ten hours is not difficult work for a competent operator. The advisory specified the affected endpoint, the missing function call, and the resulting capability. For an attacker who already had a generic WebSocket client on hand, the remaining work was wiring up the endpoint URL and receiving the shell. This is, in 2026, the new floor for time-to-exploit on disclosed vulnerabilities in the AI tooling space.
The Comparison Window: Marimo vs. Langflow vs. Historical Baselines
The Marimo timeline did not appear in a vacuum. The Sysdig report explicitly references the prior incident with Langflow CVE-2026-33017, which was exploited approximately twenty hours after disclosure. That earlier incident itself was considered fast at the time. CVE-2026-39987 cut the window in half.
The historical baseline is much longer. For most of the 2010s and early 2020s, the median time-to-exploit for disclosed CVEs was measured in days or weeks, not hours. When Project Discovery published Nuclei templates in the days following a major disclosure, that was considered fast. When Mandiant’s M-Trends reports tracked time-to-weaponization, the numbers were typically in the dozens of days.
What changed in 2026 is the combination of three things. Advisory feed monitoring is now fully automated. Every major project’s security advisory page is being scraped by attacker tooling within minutes of publication. Exploit construction from advisory text has become trivial for the most common bug classes (missing authentication, path traversal, SSRF, command injection) because the bug shape is recognizable and the advisory typically discloses the affected endpoint. AI-assisted exploit development is now real, and while we cannot prove the Marimo exploit was AI-assisted, the time pattern is consistent with operators using LLM-based tooling to rapidly transform advisory descriptions into working exploit code.
The composite effect is that the time-to-weaponization curve has compressed by roughly an order of magnitude in eighteen months for this class of vulnerability. The Marimo incident is not the new normal. It is the signal that the new normal has already arrived.
Who Is Affected — And Who Doesn’t Yet Know They Are
The most operationally consequential question for any security team reading this is the simplest one: do we have Marimo in our environment?
The answer is harder than it should be, because Marimo is the kind of tool that gets installed by individual data scientists or ML engineers without going through formal procurement. It can arrive in any of the following ways, none of which will appear in a typical software asset inventory:
- Direct pip installation by an individual developer (
pip install marimo) - As a transitive dependency of an internal data science platform or template
- Inside a Docker image built by a data team for shared notebook hosting
- Pre-installed in a managed notebook offering that vendors a Marimo-compatible interface
- As part of an MLOps pipeline where notebook execution is one of several runtime targets
- Embedded in a development sandbox distributed by an internal AI tooling team
This is the same discovery problem that has historically applied to Jupyter and is now applying to every AI notebook tool. The traditional asset inventory tools are not designed to find Python packages installed in user home directories or in container images that were built outside the central CI pipeline.
Endor Labs notes in their technical write-up that internet-wide visibility into exposed Marimo instances is easy to underestimate. A search on the default Marimo port (2718) shows only a handful of direct listeners in large internet-wide datasets. The actual exposed population is materially larger because most production deployments front Marimo behind a reverse proxy on standard HTTP ports (80, 443, 8080, 8443), where it is indistinguishable from any other HTTP service unless you specifically fingerprint the response.
The honest expectation is that tens to hundreds of internet-reachable Marimo instances remain vulnerable as of the date of this article. That is Endor Labs’s estimate, and we have no reason to dispute it. Internal-only Marimo deployments are not safe either — they are simply behind a different perimeter, and the question is whether that perimeter holds against an attacker who has already compromised one workstation in the environment.
Why a Notebook Server Compromise Is Not Like a Web Server Compromise
When a security team triages a remote code execution vulnerability in a production web application, the standard mental model is: assume the attacker has the privileges of the web server process, the database connection strings the application uses, and lateral access to whatever else lives in the same network segment. That model is well calibrated, well understood, and well exercised. Most security teams have run incident response against compromised web servers many times, and the playbook is mature.
A compromised AI/ML notebook server is a structurally different incident. The reason is that the process running the notebook is, by design, the same process that runs arbitrary user code. A web server process executes the application’s code and only the application’s code. A notebook server process executes whatever the data scientist or ML engineer typed into the most recent cell. That includes credentials loaded from environment variables, API keys read from .env files, model artifacts pulled from cloud object storage, training datasets streamed from data lakes, and connection strings to internal databases that the notebook user happened to have on hand because they were debugging a query last week.
The implication is that an attacker who reaches a Marimo process gets a much wider blast radius than an attacker who reaches a typical web server. They are not limited to whatever the application was designed to access. They are limited to whatever the human user of the notebook had access to, in the cumulative sense — every credential that has ever been loaded into the notebook session, every dataset that has been read, every API endpoint that has been queried.
This is the framing the rest of this part is built around. A Marimo compromise is best understood as a credential harvesting incident with lateral access into the entire AI development environment, not as a single-server breach.
The AI/ML Toolchain Credential Exposure Matrix (Axis Intelligence)
The matrix below is original to this analysis. We have not seen another publication produce a comparable artifact for the Marimo incident specifically, and the Cloud Security Alliance research note — the closest thing in the public record — covers the conceptual ground in prose without producing a triage-ready table.
For each credential class typically present in an AI/ML development environment, the matrix lists what the credential authorizes, the most likely exposure path on a Marimo host, and the immediate post-incident action required.
| Credential class | What it authorizes | Likely exposure path on a Marimo host | Post-incident action priority |
|---|---|---|---|
| LLM provider API keys (OpenAI, Anthropic, Cohere, Mistral) | Direct API queries on the victim organization’s account, billing exposure, model and prompt metadata leakage | .env file in working directory; environment variables in process memory; Python module config files | P0 — rotate within 1 hour |
| Cloud provider credentials (AWS, GCP, Azure) | Lateral access to compute, object storage, IAM roles, secret managers, billing | ~/.aws/credentials, ~/.config/gcloud/, ~/.azure/ directories; IMDSv1/v2 metadata service if running on cloud VMs | P0 — rotate within 1 hour |
| Cloud instance metadata service tokens | Whatever the IAM role attached to the host VM permits | IMDS endpoint reachable from compromised process | P0 — review IAM role scope |
| SSH private keys | Lateral movement to other hosts, source repository access | ~/.ssh/id_rsa, ~/.ssh/id_ed25519, agent forwarding sockets | P0 — rotate and re-key within 4 hours |
| Git credentials (GitHub, GitLab, Bitbucket tokens) | Source code read/write access, CI/CD trigger access | ~/.git-credentials, ~/.netrc, environment variables, GitHub CLI cache | P0 — revoke within 1 hour |
| Database connection strings (PostgreSQL, MySQL, Snowflake, BigQuery, Databricks) | Read or write access to data warehouses, transactional databases | Notebook variables, connection-pooling libraries, .env files | P1 — rotate within 4 hours |
| Model artifact storage credentials (Hugging Face, Weights & Biases, MLflow) | Read/write access to fine-tuned models, experiment tracking data, training metadata | Tool config files in user home; CLI cache directories | P1 — rotate within 4 hours |
| Data warehouse SSO tokens | Cached interactive session access to analytics platforms | Tool-specific cache directories; browser cookies if a browser was launched from the host | P1 — invalidate sessions |
| Vault / secret manager tokens (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager) | Time-bounded but high-value access to a wide range of secrets | Environment variables, agent socket files | P0 — revoke and reissue |
| Slack / Teams / messaging webhooks | Posting messages as the integration; data exfiltration channel | Notebook variables, integration config files | P2 — rotate within 24 hours |
| Fine-tuned model weights | Direct intellectual property exposure | Mounted volumes; cached downloads; in-memory model state | P1 — assume exfiltrated |
| Training dataset access tokens | Read access to PII-bearing or trade-secret data | Dataset library cache; cloud storage credentials | P0 — assume access occurred |
The matrix is meant to be read as a triage checklist. Walk down the rows. For each one, ask: was this credential class accessible from the compromised Marimo host? If yes, execute the post-incident action at the listed priority. The matrix is not exhaustive; it is calibrated to the credentials we have seen most commonly in real AI/ML development environments.
The second column is the part that distinguishes this from a generic incident response checklist. The credentials in an AI/ML environment do not just authorize access to one system. They authorize access to the systems that contain the organization’s AI work itself — the training data, the model weights, the fine-tuning pipelines, the experiment tracking, and the production inference endpoints. A successful exploitation of CVE-2026-39987 is, in many environments, a direct path to the most sensitive intellectual property the organization owns.
What an Attacker Actually Did, Based on the Sysdig Honeypot Observation
The Sysdig Threat Research Team observed the actual sequence of actions an attacker took inside their compromised honeypot Marimo instance. The sequence is worth reproducing because it tells you exactly what to look for in your own incident logs.
After completing the WebSocket handshake to /terminal/ws and receiving the PTY shell, the attacker performed the following actions, in this order:
- Confirmed shell access with a basic command (typically
whoami,id, orpwd). - Enumerated the working directory by listing every file accessible from the current path.
- Read the contents of every file in that directory. This is the credential harvesting step. An attacker reading every file is looking specifically for
.env, configuration files, API key exports, and connection strings. - Searched for SSH keys in the standard locations (
~/.ssh/). - Completed and disconnected within approximately three minutes total.
This is a manual operation by a competent operator, not an automated mass-scanner. The pattern is consistent with an attacker working a list of targets, spending a few minutes per target to extract maximum value, and moving on. The three-minute completion time is faster than most human triage workflows can react. By the time a security team’s first alert fires, the credential exfiltration is already done.
The implication for detection is uncomfortable but worth stating directly: detection-and-response cannot save you on this CVE. The exploitation window is too short and the attacker workflow is too fast. The only effective control is patching before exploitation or, failing that, assuming compromise and rotating every credential the host had access to.
Detection Methodology: Finding Your Marimo Exposure
Even though detection cannot prevent the credential theft, it remains essential for two reasons. First, you need to know whether you are exposed in order to patch. Second, you need to know whether you were exploited in order to scope your incident response correctly. The detection methodology below is calibrated for both.
Step 1: Inventory all Marimo installations
Marimo is a Python package, and the most reliable way to find it is to query every Python environment you have. The discovery sweeps below should be run across every host you control.
On individual workstations and servers:
# Check default Python environments
pip list 2>/dev/null | grep -i marimo
pip3 list 2>/dev/null | grep -i marimo
Across virtualenvs and conda environments:
# Find virtualenv-based installs
find / -type f -name "marimo" 2>/dev/null
find / -type d -name "marimo" 2>/dev/null | grep -i site-packages
# Conda environments
conda env list 2>/dev/null | tail -n +3 | awk '{print $1}' | while read env; do
conda list -n "$env" 2>/dev/null | grep -i marimo && echo " ^^ in env: $env"
done
Across container images:
For container-based environments, query your container registry for any image that has Marimo installed. The most reliable approach is to scan with Trivy, Grype, or your existing container vulnerability scanner — most reputable scanners had detection rules for CVE-2026-39987 within hours of disclosure.
# Trivy example
trivy image --severity CRITICAL --vuln-type library your-registry/your-image:tag
# Grype example
grype your-registry/your-image:tag --only-fixed
Step 2: Identify network-reachable instances
Once you know where Marimo is installed, you need to know which of those installations are reachable over the network — and from where.
Local listening port check:
# Check for Marimo listening on default port 2718
ss -tlnp 2>/dev/null | grep -E '2718|marimo'
netstat -tlnp 2>/dev/null | grep -E '2718|marimo'
lsof -iTCP -sTCP:LISTEN 2>/dev/null | grep -i marimo
Internet-facing exposure check:
If you operate any public-facing infrastructure, run an external scan against your IP ranges from outside your perimeter. Internal network scans will not reveal what an external attacker can see. Tools like Nmap can identify exposed services:
nmap -p 2718,80,443,8080,8443 -sV --script=http-title your.public.ip.range
The HTTP title and response headers should be enough to fingerprint a Marimo instance. Pay particular attention to instances fronted on standard HTTP ports behind reverse proxies, because those are the ones most likely to be missed by inventory tools that only check the default port.
Step 3: Search for evidence of exploitation
For any Marimo instance that was network-reachable prior to April 8, 2026, the next step is to determine whether it was actually exploited. This is the highest-value forensic question, because the answer determines whether you are running an “apply patch and move on” workflow or a full incident response.
Web server logs:
If your Marimo instance was behind a reverse proxy (nginx, Caddy, Traefik), check the access logs for requests to /terminal/ws:
# nginx default access log location
grep -E '/terminal/ws' /var/log/nginx/access.log*
# Caddy
grep -E '/terminal/ws' /var/log/caddy/*.log
# Generic search across common log locations
find /var/log -type f -name "*.log*" -exec grep -l '/terminal/ws' {} \;
Any successful WebSocket upgrade request to /terminal/ws from an unexpected source IP, particularly one occurring on or after April 8, 2026, should be treated as a strong indicator of compromise.
Marimo application logs:
Marimo writes its own application logs. The location depends on how it was launched. Check both standard output capture (if launched under systemd, this is in the journal; if launched manually, in the terminal scrollback) and any log file paths configured in your Marimo deployment.
# systemd journal
journalctl -u marimo --since "2026-04-08" | grep -i terminal
# Manual log search
find / -type f -name "*marimo*log*" 2>/dev/null
Process artifact evidence:
If the Marimo process is still running on the suspect host, examine its open file descriptors and recent file accesses:
# Find the Marimo process
pgrep -af marimo
# For each PID, check open files
for pid in $(pgrep -f marimo); do
echo "=== PID $pid ==="
ls -la /proc/$pid/fd/ 2>/dev/null | head -50
cat /proc/$pid/cmdline 2>/dev/null | tr '\0' ' '
echo
done
Look for unexpected file descriptors pointing to credential locations, SSH key files, or .env files that the legitimate notebook user would not have opened recently.
Indicator-of-compromise feeds:
The Sysdig Threat Research Team published indicators of compromise in their original report covering the in-the-wild exploitation. IPs, command patterns, and behavioral signatures from that report should be ingested into your SIEM and run against historical logs from April 8, 2026 onward.
Step 4: Compromise scoring
Based on the four detection steps above, classify each Marimo instance into one of the following categories. The category determines your response.
| Category | Condition | Response |
|---|---|---|
| Confirmed safe | Marimo not present, OR present but already on version 0.23.0+ before April 8, 2026 | Patch verification only |
| Patched, never exposed | Marimo present, was on a vulnerable version, but never network-reachable beyond a tightly trusted segment | Upgrade to 0.23.0+. No incident response. |
| Patched, was exposed, no IoC match | Marimo present, was on a vulnerable version, was network-reachable, no evidence of /terminal/ws access in logs | Upgrade. Rotate credentials as a precaution. Document. |
| Confirmed compromised | Marimo present, was vulnerable, was reachable, log evidence of /terminal/ws access from an untrusted source | Full incident response. Execute the playbook below. |
The middle two categories are the largest in practice. Most organizations will end up in the “patched, was exposed” or “patched, never exposed” buckets. A small number will end up in the “confirmed compromised” bucket and need to run the full playbook.
Incident Response Playbook for Confirmed Compromised Hosts
If your detection methodology identified a confirmed compromise, the following playbook is the minimum required response. Each step is time-bounded because the credential theft window observed by Sysdig was three minutes — meaning the credentials are gone, and the only thing you can do is invalidate them faster than the attacker can use them.
Hour 0 to Hour 1: Containment and credential rotation
- Disconnect the affected host from the network. Do not power it off — you will need the running state for forensic analysis. Use firewall rules or hypervisor-level network isolation.
- Rotate every credential identified in the AI/ML Toolchain Credential Exposure Matrix above as P0. This means LLM provider API keys, cloud provider access keys and IAM role credentials (where rotatable), SSH private keys, Git credentials, and any vault / secret manager tokens. Rotate first, investigate later.
- Revoke active sessions for any cloud console, internal application, or SaaS tool whose credentials were on the compromised host.
- Trigger an emergency change ticket for the production environment if the compromised host had access to deployment credentials. Assume the deployment pipeline is now part of the incident scope.
Hour 1 to Hour 4: Investigation and scoping
- Capture forensic evidence from the running compromised host: process list, network connections, recent file accesses, shell history. The
volatilityframework is the standard tool for memory capture if you have the discipline to use it; for most teams, capturing/proc/*/cmdline,/proc/*/environ, and bash history files is sufficient. - Review log evidence for the time window from the first observed
/terminal/wsaccess through the present. Look for outbound connections from the compromised host to unfamiliar destinations (data exfiltration), connections from the host to internal systems (lateral movement), and any cloud API calls made with the compromised credentials. - Pull cloud audit logs (AWS CloudTrail, GCP Cloud Audit Logs, Azure Activity Log) for the time window starting at the first known compromise indicator. Look for API calls made from unfamiliar source IPs using the compromised credentials.
- Identify the credential blast radius — the set of resources accessible by the credentials that were on the host, even if you have already rotated them. This is the realistic upper bound of what the attacker could have touched.
Hour 4 to Hour 24: Remediation and hardening
- Rebuild the affected host from a known-good image. Do not patch in place. The attacker had shell access; persistence mechanisms may be in place that are not visible to standard tooling.
- Upgrade the rebuilt host to Marimo 0.23.0 or later before reconnecting it to the network.
- Verify the patch by attempting an unauthenticated WebSocket connection to
/terminal/wsfrom a network-reachable client. The connection should be refused. - Audit the rebuilt deployment for the same exposure pattern: ensure that the Marimo process runs as a non-root user, is not bound to public network interfaces unless absolutely necessary, and is fronted by a reverse proxy that requires authentication at the proxy layer in addition to the application layer.
Hour 24 onward: Disclosure and lessons learned
- Disclose the incident to affected internal stakeholders, customers (if applicable), and regulators (if your jurisdiction requires it). For credential exposure incidents involving cloud provider credentials, the disclosure timing is typically governed by the Service Agreement with the cloud provider.
- Conduct a postmortem specifically focused on why the Marimo deployment was exposed and how the exposure was missed by your existing controls. The most common findings will be that the Marimo instance was installed by an individual outside the central inventory process, and that the reverse proxy in front of it was not configured to require authentication.
- Implement the structural controls described in Part 3 to prevent similar incidents in other AI/ML toolchain components.
A Note on the Limits of This Playbook
This playbook is calibrated for organizations that have a functional security operations capability and the authority to make rapid decisions about credential rotation. It is not a substitute for a relationship with an incident response retainer if you do not have internal capacity. If your organization is reading this article in the middle of an active compromise and does not have either internal capacity or a retainer in place, the CISA Incident Response Resources page is the right starting point for emergency assistance.
The playbook is also written for the worst case. Most Marimo deployments were not exploited. The attacker pool is real but finite, and the population of internet-reachable Marimo instances was a few thousand at most. If your detection methodology returns no evidence of exploitation, the appropriate response is “patch, rotate as a precaution, document, move on” — not the full playbook above.
Why a Generalized Framework Is Necessary
If the only outcome of CVE-2026-39987 was a patched Marimo instance, this article would not need a Part 3. Patch management is a solved problem at the procedural level — what makes the Marimo incident worth a dedicated framework is that the same vulnerability shape will appear in every AI notebook tool, every agentic AI development platform, and every LLM orchestration framework released in the next eighteen months. The bug is structural: a server that exposes multiple endpoints, of which one or more grants powerful capabilities, with inconsistent authentication enforcement across the endpoint set. CVE-2026-39987 is the textbook example. It is not a unique example.
The pattern has already manifested in Langflow CVE-2026-33017, the prior incident the Sysdig report references. It has manifested in earlier vulnerabilities affecting Jupyter Server, n8n, and several MLOps platforms. It will manifest again. The defender response cannot be “patch each one as it comes out and hope we are fast enough.” The exploitation window has compressed below the median patch deployment time for most organizations. The only durable response is to prevent the exposure shape itself, not the individual bug instances.
This part of the analysis offers that prevention framework. It is structured as a security baseline for AI notebook and orchestration servers — a set of controls that, if implemented, would have prevented CVE-2026-39987 from being exploitable in your environment regardless of whether you had heard of Marimo before April 8, 2026. The framework is original to this analysis, mapped to recognized standards (NIST CSF 2.0, OWASP Top 10, OWASP API Security Top 10, and CIS Controls v8), and structured to be implementable by a small security team.
The Notebook Server Security Baseline (Axis Intelligence Framework)
The baseline is organized into five control domains. Each domain contains specific controls with explicit framework mappings. Implement them in order — earlier controls are dependencies for later ones.
Domain 1: Identification and Inventory
The most common reason CVE-2026-39987 caught organizations off guard was that they did not know they had Marimo installed. AI notebook tools are introduced by individual developers, propagate through internal templates, and end up in container images that were never reviewed by the security team. You cannot patch what you cannot see.
Control 1.1 — Authoritative AI tooling inventory. Maintain a single authoritative inventory of AI/ML tools deployed in any environment your organization controls, refreshed at least weekly. The inventory must include the tool name, version, deployment location (host, container, orchestrator), exposure status (network reachability), and the responsible team. This maps to NIST CSF 2.0 ID.AM-1, ID.AM-2, ID.AM-7 (asset management) and CIS Control 1 (Inventory and Control of Enterprise Assets) and CIS Control 2 (Inventory and Control of Software Assets).
Control 1.2 — Continuous Python environment scanning. Run automated scans across every host that may execute Python code to enumerate installed packages. Use Software Bill of Materials (SBOM) generation tools that produce CycloneDX or SPDX output for centralized ingestion. Scan virtualenvs, conda environments, system Python, container images, and notebook server kernels. Maps to NIST CSF ID.AM-2.
Control 1.3 — Container image scanning at build and runtime. Every container image used for AI/ML workloads must be scanned at build time by a vulnerability scanner with current CVE coverage, and re-scanned in production at least daily. Use Trivy, Grype, or your enterprise scanner. Block deployment of images with critical vulnerabilities older than your defined patch window. Maps to CIS Control 7 (Continuous Vulnerability Management).
Control 1.4 — Shadow IT discovery for notebook tools. Implement a discovery process that catches notebook installations performed by individual developers outside formal procurement. Approaches include: Python environment scanning across endpoints, network-level fingerprinting of notebook server protocols, and integration with your endpoint management tool to flag installation events for known notebook packages. Maps to NIST CSF ID.AM-1.
Domain 2: Network Exposure Reduction
The second most common reason CVE-2026-39987 was exploitable was that vulnerable Marimo instances were reachable from untrusted networks. The mitigations in this domain reduce the reachable population so that even an unpatched instance is not exploitable from outside a tightly controlled segment.
Control 2.1 — Default deny on notebook server network exposure. AI notebook servers must be deployed with a default-deny network policy. The Marimo, Jupyter, Langflow, or n8n process should bind only to a loopback interface unless there is a documented and approved business reason for broader exposure. Enforce via host firewall rules (iptables, nftables, or ufw), cloud security group rules, and network policy in Kubernetes-based deployments. Maps to NIST CSF PR.AC-5 (network integrity is protected) and OWASP API1:2023 (broken object level authorization, broadly interpreted).
Control 2.2 — Mandatory authentication at the reverse proxy layer. When a notebook server must be exposed beyond loopback, it must be fronted by a reverse proxy that enforces authentication independently of the application layer. The reverse proxy must require valid credentials before forwarding any request to the upstream notebook server. This is a defense-in-depth control: even if the notebook application has a missing-authentication bug like CVE-2026-39987, the proxy layer prevents unauthenticated access from reaching the application at all. Recommended implementations: oauth2-proxy, Authelia, or your enterprise SSO gateway. Maps to OWASP A07:2021 (Identification and Authentication Failures) and NIST CSF PR.AC-1 (identities and credentials are issued, managed, verified, revoked, and audited).
Control 2.3 — Egress filtering on notebook hosts. Notebook servers that legitimately need outbound network access (to fetch datasets, query APIs, etc.) should have that access constrained to an explicit allowlist of destinations. This dramatically reduces the data exfiltration surface in the event of a successful compromise. Implement via egress firewall rules or service mesh policy. Maps to NIST CSF PR.PT-4 (communications and control networks are protected).
Control 2.4 — Network segmentation between notebook hosts and production. Notebook servers should not share a network segment with production services. The most common lateral movement path in an AI/ML compromise is from a development notebook host to a production data warehouse or production inference endpoint. Enforce segmentation via VPC design, security groups, or service mesh policy. Maps to CIS Control 12 (Network Infrastructure Management).
Domain 3: Identity and Authentication
Even with network exposure reduced, the application layer still needs robust authentication. This domain addresses the controls that would have made the missing-validate_auth()-call bug irrelevant in practice.
Control 3.1 — No anonymous notebook access, ever. Disable any “open” or “anonymous” mode in your notebook server configuration. For Marimo specifically, ensure you are running in a mode that requires an access token. For Jupyter, ensure c.NotebookApp.token is set to a long random value or that authentication is delegated to an external provider. Maps to OWASP A07:2021.
Control 3.2 — Federated authentication via SSO. Notebook servers used by more than one person must authenticate users through your identity provider, not via shared static tokens. Use OIDC or SAML integration through the reverse proxy described in Control 2.2. This eliminates the “shared notebook URL with token in the query string” anti-pattern that is the most common authentication weakness in real-world notebook deployments. Maps to NIST CSF PR.AC-1, PR.AC-7.
Control 3.3 — Short-lived credentials, no persistent secrets in .env files. This is the control that most directly limits the blast radius of a successful exploitation. Notebook hosts should not have long-lived API keys or cloud credentials in .env files or environment variables. Use workload identity federation (GCP), IAM Roles for Service Accounts (AWS EKS), or the HashiCorp Vault dynamic secrets model to issue credentials with short TTLs and tightly scoped permissions. Maps to NIST CSF PR.AC-1 and the broader zero trust architecture model in NIST SP 800-207.
Control 3.4 — No interactive terminal features in production notebook deployments. This is the Marimo-specific control derived directly from the CVE. The integrated terminal feature is what made CVE-2026-39987 exploitable as a shell-granting bug. If you do not need the terminal feature in a given deployment, disable it. Marimo, Jupyter, and most other notebook platforms support running in a mode that excludes the terminal endpoint entirely. Maps to CIS Control 4 (Secure Configuration of Enterprise Assets and Software).
Domain 4: Process Hardening and Privilege Limitation
If a notebook server is compromised despite the controls above, this domain ensures that the attacker has the smallest possible set of privileges to work with.
Control 4.1 — Notebook processes never run as root. Run notebook server processes as a dedicated, low-privilege user account. The default Marimo Docker image runs as root in many configurations; this is exactly the wrong default for a tool that exposes a terminal feature. Override the Dockerfile USER directive or use a Kubernetes securityContext to enforce non-root execution. Maps to CIS Control 5 (Account Management).
Control 4.2 — Read-only filesystem where possible. Container-based notebook deployments should mount the root filesystem as read-only and provide writable storage only at specific paths the notebook genuinely needs (typically /tmp and a designated workspace directory). This eliminates many attacker persistence mechanisms. Maps to NIST CSF PR.IP-1 (baseline configuration of IT systems is created and maintained).
Control 4.3 — No host SSH keys or cloud credential files inside the notebook process’s accessible filesystem. SSH keys and cloud credential files must not be in any directory the notebook process can read. Move them to a directory inaccessible to the notebook user, mount them only when explicitly needed by a specific notebook task, and never as a persistent default. Maps to NIST CSF PR.AC-4 (access permissions and authorizations are managed).
Control 4.4 — Container instance metadata service hardening. If notebook hosts run on cloud VMs, the cloud instance metadata service is reachable from the compromised process. On AWS, require IMDSv2 and limit the IAM role attached to notebook hosts to the minimum permissions required. On GCP, scope the service account similarly. On Azure, use managed identities with minimum role bindings. Maps to NIST CSF PR.AC-4 and the relevant cloud provider security baselines.
Control 4.5 — Resource limits on notebook processes. Apply CPU, memory, and process limits via cgroups, Kubernetes resource limits, or systemd unit configuration. This does not prevent compromise but does limit the attacker’s ability to mine cryptocurrency or pivot to compute-intensive lateral movement. Maps to CIS Control 4.
Domain 5: Detection and Response
The final domain accepts that prevention will sometimes fail and ensures that when it does, you find out fast enough to respond effectively.
Control 5.1 — Centralized logging from notebook servers. Notebook server logs (HTTP access logs, application logs, WebSocket connection logs) must be shipped to a centralized log store for retention and analysis. Local-only logs are insufficient because the first thing many attackers do is delete them. Maps to NIST CSF DE.AE-3 (event data are collected and correlated from multiple sources and sensors) and CIS Control 8 (Audit Log Management).
Control 5.2 — WebSocket-aware logging at the reverse proxy. The reverse proxy in front of your notebook server must log every WebSocket upgrade request, including the source IP, destination path, and authentication status. Standard nginx and Caddy access log formats capture this with appropriate format strings. Maps to NIST CSF DE.CM-1 (the network is monitored to detect potential cybersecurity events).
Control 5.3 — Alerting on unauthenticated access to sensitive endpoints. Any unauthenticated request to a notebook server endpoint that should require authentication must trigger a real-time alert. Threshold the alert to avoid noise from health checks and bots, but ensure that the first successful unauthenticated WebSocket upgrade to a sensitive endpoint generates a paged alert. Maps to NIST CSF DE.CM-7.
Control 5.4 — IoC ingestion from CVE feeds. Subscribe to threat intelligence feeds that publish indicators of compromise for notebook-related CVEs. The Sysdig Threat Research Team, GreyNoise, and the CISA Known Exploited Vulnerabilities catalog are appropriate sources. Ingest the IoCs into your SIEM and run them against historical logs. Maps to NIST CSF DE.CM-1, DE.AE-2.
Control 5.5 — Scheduled exposure scanning. Run external scans against your public IP ranges at least weekly to identify any newly exposed notebook services. The scan should identify Marimo (default port 2718), Jupyter (default ports 8888, 8889), Langflow (default port 7860), n8n (default port 5678), MLflow (default port 5000), and other common AI tooling ports, regardless of whether they appear in your asset inventory. Maps to CIS Control 7.
The Cross-CVE Comparison: Marimo, Langflow, and the Trend Line
Marimo is not the first AI tool to exhibit this exact vulnerability shape. The table below compares the three most operationally significant AI notebook and orchestration CVEs of the past eighteen months. The pattern is the comparison’s reason for existing.
| Vulnerability | Project | Disclosed | CVSS | Time-to-exploit | Bug class | Fixed in |
|---|---|---|---|---|---|---|
| CVE-2026-39987 | Marimo | April 8, 2026 | 9.3 (v4.0) | ~9h 41m | Pre-auth RCE via missing WebSocket authentication | 0.23.0 |
| CVE-2026-33017 | Langflow | Earlier in 2026 | High (per Sysdig) | ~20h | Pre-auth RCE | Patched in subsequent release |
| (prior period) | (multiple Jupyter / orchestration platforms) | 2024–2025 | Various | Days to weeks | Various authentication and command injection issues | Patched per advisory |
The trend is unambiguous. Time-to-exploit has compressed from days or weeks to hours. The bug shapes are similar across projects because the architectural patterns are similar. Project sizes are not protective: Marimo is roughly an order of magnitude smaller than Langflow, and the Marimo exploitation window was half as long. The fact that a project is small or niche does not make its vulnerabilities less attractive to attackers monitoring advisory feeds. It often makes them more attractive, because a smaller project is less likely to have a hardened production deployment ecosystem around it.
The forward-looking implication is that the next CVE in this category is already in the pipeline. We do not know which project will produce it. We do know that the exploitation window will continue to be measured in hours, not days, and that the only durable defender posture is to assume the next disclosure is imminent and to have the baseline controls in this part already implemented.
A Minimum Viable Implementation Path for Small Teams
The five-domain framework above is comprehensive. For a small security team without the capacity to implement everything immediately, the following is the minimum viable implementation path that captures the highest-leverage controls. Implement these first, and add the rest as capacity allows.
- Inventory every Python environment in your organization (Control 1.1, 1.2, 1.4). One week of work for a small team.
- Front every notebook server with an authenticating reverse proxy (Control 2.2). Two days of work per notebook server, scalable as templated configuration.
- Disable interactive terminal features in production notebook deployments (Control 3.4). One configuration change per server.
- Move all long-lived credentials off notebook hosts (Control 3.3). The hardest control on the list, and the one with the largest blast radius reduction. Plan for two to four weeks.
- Enable centralized logging and WebSocket-aware logging at the reverse proxy (Control 5.1, 5.2). One day of work plus log volume cost.
Those five controls would have made CVE-2026-39987 a non-event in your environment. They will make the next equivalent CVE a non-event as well.
Open Questions Worth Continuing to Watch
The Marimo incident is still unfolding as of the publication of this article. The following questions are not yet answered in the public record. We list them so that the next iteration of this analysis can be updated against a known checklist, and so that defenders reading this article in real time know which information gaps to expect to fill in over the coming weeks.
1. How many internet-reachable Marimo instances were ultimately compromised? Sysdig observed exploitation attempts against honeypots within ten hours. They have not yet published an estimate of the total compromised population. Endor Labs estimated that “tens to hundreds” of vulnerable instances may remain exposed at the time of their write-up. The actual compromised count, when it lands, is the most important number for understanding the real-world impact.
2. Was the Marimo exploit AI-assisted? The pattern of behavior — building a working exploit from advisory text in under ten hours, with no public PoC — is consistent with both a competent human operator and an LLM-assisted exploit development workflow. We do not yet have direct evidence of which it was. Sysdig’s public report does not address the question. If subsequent analysis confirms AI-assisted exploitation, the implications for the broader compression of time-to-weaponization are substantial.
3. Will CVE-2026-39987 be added to the CISA Known Exploited Vulnerabilities catalog? As of this writing, the CISA KEV catalog has not added the CVE. Given the confirmed in-the-wild exploitation observed by Sysdig, an addition seems likely within days to weeks. Federal agencies subject to Binding Operational Directive 22-01 will have a specific patch deadline once the addition lands. Private sector defenders should not wait for the CISA listing to act.
4. Did any of the compromised instances have access to LLM provider production accounts at scale? The credentials accessible from a typical Marimo host include LLM provider API keys. If any of those keys belonged to high-volume production accounts at OpenAI, Anthropic, or another major provider, the financial exposure to the affected organizations could be substantial — even if no other lateral movement occurred. We have not seen reports of confirmed billing-driven incidents yet.
5. How will the Marimo project’s security disclosure process evolve? The initial OSV entry for CVE-2026-39987 was flagged by Endor Labs as understated on the affected versions. This is a small data quality issue that nonetheless points to the broader challenge of vulnerability metadata accuracy in the open-source ecosystem. The Marimo project’s response will be a useful indicator of how mature its security process becomes after this incident.
6. Will any class action or regulatory enforcement follow? Notebook compromise incidents have not historically attracted the same regulatory attention as customer-data breaches, but the credentials-and-IP angle may shift that calculus. We are not aware of any active enforcement at this time.
We will update this article as these questions are answered.
What Marimo Did Right
It would be easy to read the preceding three parts as a critique of the Marimo project. It is not. The bug in CVE-2026-39987 is real and the project deserves the scrutiny it has received, but the response from the maintainers has been substantially better than the median for open-source projects of similar size. We want to be explicit about that, because the security community has a tendency to amplify failure modes and ignore well-handled disclosure cycles.
Specifically, the Marimo project did the following things correctly:
- Shipped a fix simultaneously with the disclosure. Version 0.23.0 was available on PyPI at the moment the advisory was published. There was no patch gap.
- Published a detailed technical advisory that named the affected endpoint, described the missing function call, and provided enough context for users to understand the severity. This is the right level of disclosure detail. Less detail would have left users unable to assess their exposure; more detail would have included a working PoC that would have accelerated exploitation.
- Coordinated with security researchers in a way that allowed Sysdig’s honeypot operation to be in place and observing in real time when the advisory dropped. The fact that we have a precise time-to-exploit measurement at all is because the disclosure process was professional enough to enable it.
- Did not minimize the issue in their public messaging. The advisory text uses the phrase “Pre-Auth RCE” without softening, which is the technically correct framing.
The right framing of the Marimo response is that a small open-source project made a fast, responsible disclosure and shipped a fix immediately. The vulnerability is the project’s failure. The disclosure is the project’s success. Both should be acknowledged.
The structural lesson is not “Marimo is insecure.” It is “the gap between fast, responsible disclosure and effective defender response is now narrower than the time defenders need to deploy patches, and the only durable answer is to harden the architectural pattern rather than chasing individual bugs.”
Frequently Asked Questions
What is CVE-2026-39987?
CVE-2026-39987 is a critical pre-authentication remote code execution vulnerability in Marimo, an open-source reactive Python notebook tool used for AI, machine learning, and data science. It carries a CVSS v4.0 score of 9.3 and affects all Marimo versions through 0.20.4. The flaw exists in the /terminal/ws WebSocket endpoint, which accepted unauthenticated connections and granted an interactive shell to the requesting client. It was disclosed on April 8, 2026, and exploited in the wild within 9 hours and 41 minutes.
How do I patch CVE-2026-39987?
Upgrade Marimo to version 0.23.0 or later. Verify the upgrade by running marimo --version and confirming the version string. For container-based deployments, update both the base image and any pinned dependency specifications, then redeploy. After patching, attempt an unauthenticated WebSocket connection to /terminal/ws from a network-reachable client; the connection should be refused.
How do I know if my Marimo instance was compromised?
Check your reverse proxy access logs and Marimo application logs for any successful WebSocket upgrade requests to /terminal/ws from unexpected source IPs, particularly any occurring on or after April 8, 2026. If your Marimo instance was network-reachable from any untrusted segment between April 8 and the time you applied the patch, treat the deployment as potentially compromised and follow the incident response playbook in Part 2.
What credentials should I rotate if my Marimo host was compromised?
At minimum: LLM provider API keys (OpenAI, Anthropic, Cohere, Mistral, others), cloud provider access keys and IAM role credentials, SSH private keys, Git credentials and personal access tokens, database connection strings, and any vault or secret manager tokens. The full credential exposure matrix is in Part 2. The rotation priority is governed by the blast radius of each credential class — rotate cloud and LLM credentials within one hour; rotate everything else within four to twenty-four hours depending on sensitivity.
How quickly was CVE-2026-39987 exploited in the wild?
The Sysdig Threat Research Team observed the first in-the-wild exploitation against their honeypots approximately 9 hours and 41 minutes after the public advisory was published, with no public proof-of-concept code available at the time. The complete credential theft operation was executed in under 3 minutes once the attacker gained shell access. This is roughly half the time-to-exploit observed for the prior Langflow CVE-2026-33017 incident.
Is CVE-2026-39987 in the CISA Known Exploited Vulnerabilities catalog?
As of this article’s publication on April 12, 2026, CVE-2026-39987 has not yet been added to the CISA KEV catalog. Given the confirmed in-the-wild exploitation, an addition is likely in the near term. Defenders should not wait for the CISA listing to act on the patch.
Why is a notebook server compromise more serious than a typical web server compromise?
A notebook server process is, by design, the same process that runs arbitrary user code. That means it typically has access to whatever credentials, datasets, model artifacts, and infrastructure the human notebook user had access to — including LLM provider API keys, cloud credentials in nearby .env files, training data, and internal database connection strings. A successful exploitation functions as a credential harvesting operation against the entire AI development environment, not just a single server.
What is Marimo, and how is it different from Jupyter?
Marimo is an open-source reactive Python notebook framework. Its key differentiator from Jupyter is a dataflow-based execution model: when a cell changes, every dependent cell re-runs automatically, ensuring code, outputs, and program state remain consistent. This eliminates Jupyter’s most common reproducibility failure mode (stale state). Marimo has approximately 19,600 GitHub stars at the time of the disclosure.
Does this vulnerability affect Jupyter as well?
No. CVE-2026-39987 is specific to Marimo’s /terminal/ws endpoint implementation. However, Jupyter Server has had its own pre-authentication and authentication-bypass vulnerabilities in past releases, and the broader pattern (notebook server endpoints with inconsistent authentication enforcement) applies across the AI/ML notebook ecosystem. The defender baseline in Part 3 is intentionally written to apply to Jupyter, Langflow, n8n, MLflow, and other AI tooling servers, not just Marimo.
Should I stop using Marimo because of this vulnerability?
No. The Marimo project responded to the disclosure correctly, shipped a fix immediately, and provided enough information for defenders to assess and remediate. Patched Marimo (version 0.23.0 or later) is no more or less secure than any other comparable notebook tool. The right response is to upgrade, implement the notebook server security baseline in Part 3, and continue using the tool.
How can I detect future vulnerabilities like CVE-2026-39987 before they are weaponized?
You cannot, in the general case. The exploitation window for this class of vulnerability has compressed below the typical patch deployment time for most organizations. The only durable response is to implement the architectural controls — particularly the reverse proxy authentication layer (Control 2.2), the credential exposure reduction (Control 3.3), and the disabling of interactive terminal features in production (Control 3.4) — so that even an unpatched instance is not exploitable from outside a trusted segment.
Final Verdict
For security operations leaders: Treat CVE-2026-39987 as an active incident if you ran Marimo on internet-reachable infrastructure prior to April 8, 2026. The detection methodology in Part 2 is the minimum required diligence. The credential rotation matrix in Part 2 is the minimum required containment. The notebook server security baseline in Part 3 is the minimum required structural response. None of these are optional.
For AI engineering and ML platform leaders: This incident is a forcing function. The growth of AI/ML tooling has outpaced the security maturity of the surrounding ecosystem, and the tools your data scientists are installing today are the source of the next CVE in this class. Implement the inventory controls in Part 3 Domain 1 within the next thirty days, and integrate AI tooling security review into your team’s onboarding for new tools. The cost of doing this proactively is dramatically lower than the cost of running incident response on every CVE that ships.
For CISOs and risk officers: The Marimo incident is the canonical example of the AI/ML toolchain risk class. It is the right artifact to take into a board briefing on AI security risk because it is concrete, the timeline is documented, the blast radius is quantifiable, and the structural lessons are general. The notebook server security baseline in Part 3 is the right framework to commit to as a risk control roadmap.
For open-source maintainers of AI tools: The Marimo project’s disclosure response is the model. Ship the fix simultaneously with the advisory. Provide enough technical detail for users to assess exposure without providing a working PoC. Coordinate with security researchers so the time-to-detection is real. Do not minimize the severity in your messaging. The community will respond well to honest, detailed disclosures.
For everyone: The new floor for time-to-exploit on disclosed pre-authentication vulnerabilities in AI tooling is approximately ten hours. That number is going to keep getting shorter. The defender response cannot be to chase each individual CVE. It has to be to harden the architectural pattern so that the next one is not exploitable in your environment regardless of whether you were paying attention on the day it was disclosed.

Cybersecurity analyst covering VPN, antivirus, privacy, and online threats. 8+ years in enterprise security operations. Tests every product he reviews.
