CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-2679-6MX9-H9XC
9.5

GHSA-2679-6MX9-H9XC: Unauthenticated Remote Code Execution in marimo Terminal WebSocket

Amit Schendel
Amit Schendel
Senior Security Researcher

Apr 9, 2026·5 min read·1 visit

PoC Available

Executive Summary (TL;DR)

The marimo notebook environment prior to version 0.23.0 exposes an unauthenticated terminal WebSocket endpoint (`/terminal/ws`). Attackers can connect to this endpoint to spawn a PTY shell, executing arbitrary commands with the privileges of the marimo server process.

An authentication bypass vulnerability in the marimo interactive Python notebook environment allows unauthenticated remote attackers to obtain interactive pseudo-terminal (PTY) shell access. The flaw resides in the terminal WebSocket endpoint, which fails to enforce required authentication checks, leading to critical remote code execution capabilities on the host system.

Vulnerability Overview

The marimo application is a reactive notebook environment for Python that provides a web-based interface backed by a local server. This server exposes several HTTP and WebSocket endpoints to facilitate interactivity, code execution, and terminal access.

The vulnerability is located within the terminal-specific WebSocket endpoint at the /terminal/ws route. In default configurations, marimo restricts access to its interactive features using an authentication token system. The server relies on a specific validation function to enforce these checks across its various communication channels.

While the primary application WebSocket route correctly implements authentication validation, the terminal endpoint omits this critical step. It strictly verifies whether the application operates in "edit mode" and confirms underlying operating system support for pseudo-terminals (PTYs). Because the endpoint fails to establish the identity of the incoming connection, any client capable of reaching the open port can initiate a connection and gain complete access to the resulting terminal session.

Root Cause Analysis

The underlying technical flaw is an instance of CWE-306: Missing Authentication for Critical Function. The marimo backend utilizes the Starlette asynchronous framework for HTTP routing and middleware execution. In this architecture, an AuthenticationMiddleware component is responsible for parsing inbound requests and populating user identity information.

However, Starlette's middleware design dictates that WebSocket connections are not automatically terminated or rejected upon missing authentication tokens unless explicitly programmed to do so within the specific endpoint handler. The marimo application standardizes this process through a validate_auth() utility function, which inspects the WebSocket connection for a valid access_token query parameter or corresponding session cookie.

In marimo/_server/api/endpoints/terminal.py, the websocket_endpoint handler dictates the connection lifecycle for the terminal interface. The implementation checks the application mode (app_state.mode != SessionMode.EDIT) and evaluates PTY support but completely lacks the required validate_auth(websocket) invocation. Consequently, the handler bridges the inbound connection directly to the PTY subsystem without verifying the source's authorization state.

Code Analysis

An analysis of the source code reveals the direct omission of the validation logic. The vulnerable implementation accepts the WebSocket object and immediately instantiates the AppState without authenticating the client session.

# Vulnerable implementation prior to 0.23.0
@router.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket) -> None:
    app_state = AppState(websocket)
    if app_state.mode != SessionMode.EDIT:
        await websocket.close(code=1008, reason="Terminal only available in edit mode")
        return
    # Execution proceeds to spawn the PTY

The fix, introduced in commit c24d4806398f30be6b12acd6c60d1d7c68cfd12a, rectifies this by explicitly invoking the missing authorization check before processing any connection state. If the authentication logic fails, the connection is safely terminated with an appropriate WebSocket status code.

# Patched implementation in 0.23.0
@router.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket) -> None:
    if not validate_auth(websocket):
        await websocket.close(code=3000, reason="MARIMO_UNAUTHORIZED")
        return
 
    app_state = AppState(websocket)
    if app_state.mode != SessionMode.EDIT:
        await websocket.close(code=1008, reason="Terminal only available in edit mode")
        return

The following diagram illustrates the vulnerable connection flow prior to the patch application.

Exploitation Mechanics

Exploiting this vulnerability requires network access to the target marimo server port, which defaults to 2718. The attacker begins by scanning for exposed instances or specifically targeting known deployment addresses.

Once a target is identified, the attacker crafts a standard WebSocket upgrade request targeting the /terminal/ws endpoint. The client intentionally omits any access_token query parameters or authentication cookies. The server receives the connection, processes the HTTP-to-WebSocket upgrade, and transitions into the handler logic.

The server confirms the SessionMode is set to edit, which is the typical operational state for an active notebook. It subsequently issues a pty.fork() system call, creating a new child process running the system's default shell executable. Standard input, output, and error file descriptors of the child process are routed to an asynchronous I/O loop that frames terminal data into WebSocket messages.

The attacker receives an interactive shell session. By transmitting appropriately framed WebSocket text messages containing shell commands, the attacker achieves arbitrary command execution on the target operating system.

Impact Assessment

This vulnerability achieves a CVSS v3.1 base score of 9.5 (Critical) due to the simplicity of the attack vector and the severity of the consequences. The vector evaluates to CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H.

The unauthenticated remote code execution occurs in the context of the user running the marimo server process. If marimo is executed by a standard user account on a developer workstation, the attacker gains full access to user files, environment variables, internal network resources, and adjacent credentials.

If the application is deployed in a server or containerized environment with elevated privileges, the compromise depth increases significantly. The absence of complex exploitation prerequisites renders this vulnerability highly reliable to exploit via automated tooling.

Remediation and Mitigation

The primary remediation for this vulnerability is immediately upgrading the marimo Python package to version 0.23.0 or later. The patch completely prevents unauthenticated connections from reaching the PTY subsystem by enforcing the standard token verification mechanism.

If immediate patching is technically infeasible, administrators must restrict network access to the marimo instance. Bind the service exclusively to local loopback addresses (127.0.0.1 or localhost) and utilize a virtual private network or SSH tunneling for remote access. Do not expose the service to zero-route addresses (0.0.0.0) on untrusted networks.

Additionally, technical analysis indicates a secondary risk related to Cross-Site WebSocket Hijacking (CSWSH). If users interact with the patched marimo server through a browser that stores active session cookies, a malicious website visited by the user could attempt to initiate a WebSocket connection. Organizations should configure marimo to validate tokens strictly through query parameters and enforce strong SameSite cookie policies.

Official Patches

marimo-teamPull Request fixing the authorization bypass
marimo-teamSecurity patch applying missing validation

Fix Analysis (1)

Technical Appendix

CVSS Score
9.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Affected Systems

marimo notebook serverPython environments utilizing marimo < 0.23.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
marimo
marimo-team
< 0.23.00.23.0
AttributeDetail
Bug ClassImproper Authorization (CWE-306)
Attack VectorNetwork (WebSocket)
Authentication RequiredNone
ImpactRemote Code Execution (RCE)
CVSS v3.1 Score9.5 (Critical)
Exploit MaturityProof of Concept Available

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059.004Command and Scripting Interpreter: Unix Shell
Execution
CWE-306
Missing Authentication for Critical Function

The software does not perform any authentication for functionality that requires a provable user identity or consumes a significant amount of resources.

Known Exploits & Detection

PulsePatch Technical AnalysisProof of concept mechanics involving websocket framing directed at the terminal endpoint.
NucleiDetection Template Available

Vulnerability Timeline

Vulnerability identified and disclosed
2026-04-08
Security patch submitted via PR #9098
2026-04-08
Fix commit merged to source tree
2026-04-08
Version 0.23.0 released on PyPI
2026-04-08

References & Sources

  • [1]GitHub Security Advisory: GHSA-2679-6MX9-H9XC
  • [2]Fix Pull Request
  • [3]Fix Commit
  • [4]Technical Analysis (PulsePatch)
  • [5]PyPI Package Release 0.23.0

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.