
CVE-2026-39987の検出および悪用ツールキット。Marimoノートブックにおける事前認証RCEです。WebSocketエンドポイントのチェックを介して脆弱なインスタンスを特定するPythonスキャナーとNmap NSEスクリプトが含まれています。
Marimo(データサイエンスおよびAI/ML向けのオープンソースPythonノートブック)における事前認証リモートコード実行の脆弱性。ターミナルWebSocketエンドポイント(/terminal/ws)は認証検証を完全にスキップする一方、隣接するノートブックエンドポイント(/ws)は正しく認証を強制します。認証されていない攻撃者は/terminal/wsに接続し、資格情報なしでホストシステム上で完全な対話型PTYシェルを取得できます。
開示から10時間以内に実環境で悪用されました。攻撃者は3分未満でAWS認証情報を窃取しました。
影響を受けるバージョン: Marimo <= 0.20.4。Marimo 0.23.0で修正済み。
| フィールド | 詳細 |
|---|---|
| CVE ID | CVE-2026-39987 |
| ベンダー | Marimo Project |
| 製品 | Marimo(Pythonノートブック) |
| 影響を受けるバージョン | <= 0.20.4 |
| CVSS v3.1 | 9.3(Critical) |
| CWE | CWE-306 — 重要な機能に対する認証の欠如 |
| 攻撃ベクトル | ネットワーク |
| 認証 | 不要 |
| ユーザー操作 | 不要 |
| エクスプロイトの成熟度 | 実環境で活発に悪用中 |
| 悪用までの時間 | 開示から約10時間 |
| 修正バージョン | Marimo 0.23.0 |
Marimoは、Jupyterの現代的代替として設計されたオープンソースのリアクティブPythonノートブックです。データサイエンス、AI/ML実験、対話型データ分析向けに構築されています。主な特徴は、自動依存関係追跡、再現可能な実行、従来のノートブックと比較してよりクリーンな開発者体験です。
MarimoはPythonおよびAI/MLコミュニティで急速に普及しており、特にJupyterが提供するものよりも構造化されたノートブックワークフローを求める実践者の間で支持を集めています。
すべてのノートブック環境と同様に、Marimoインスタンスは通常、機密リソースへのアクセス権を持ちます: クラウド認証情報(AWS、GCP、Azure)、データベース接続文字列、AIサービス用APIキー(OpenAI、Anthropicなど)、内部ネットワークアクセス。従来のWebアプリケーションとは異なり、ノートブックは任意のコードを実行するように設計されています。それがノートブックの核となる目的です。
この組み合わせにより、ノートブック環境における認証バイパスは特に壊滅的な影響を及ぼします。``` Typical Marimo Deployment:
┌──────────────┐ ┌────────────────────────────────┐ │ │ HTTP │ Marimo Server │ │ Browser │────────>│ │ │ (User) │ │ ┌──────────────────────────┐ │ │ │<────────│ │ /ws (Notebook) │ │ └──────────────┘ WS │ │ ✅ validate_auth() │ │ │ └──────────────────────────┘ │ │ │ │ ┌──────────────────────────┐ │ │ │ /terminal/ws │ │ │ │ ❌ NO AUTH CHECK │ │ │ └──────────────────────────┘ │ │ │ │ ┌──────────────────────────┐ │ │ │ Python Environment │ │ │ │ .env files │ │ │ │ AWS credentials │ │ │ │ API keys │ │ │ └──────────────────────────┘ │ └────────────────────────────────┘
---
## 脆弱性の詳細
### 2つのWebSocketエンドポイント
Marimoのサーバーは、さまざまな機能のために複数のWebSocketエンドポイントを実装しています。2つの主要なエンドポイント間の重要な違いは、認証チェックの有無です。```
Authentication Flow Comparison:
/ws (Notebook WebSocket):
┌─────────┐ ┌───────────────┐ ┌──────────┐ ┌───────────┐
│ Connect │───>│ validate_auth │───>│ Accept │───>│ Notebook │
└─────────┘ └───────┬───────┘ └──────────┘ └───────────┘
│
❌ Reject if
not authenticated
/terminal/ws (Terminal WebSocket):
┌─────────┐ ┌───────────────┐ ┌──────────┐ ┌───────────┐
│ Connect │───>│ Check mode & │───>│ Accept │───>│ PTY Shell │
└─────────┘ │ platform only │ └──────────┘ └───────────┘
└───────────────┘
⚠️ No auth check!
Anyone gets a shell!
ノートブックエンドポイント(/ws)は、WebSocket接続を受け入れる前にユーザーの身元を検証するためにvalidate_auth()を正しく呼び出します。これは期待されるセキュリティ動作です。
ターミナルエンドポイント(/terminal/ws)は、サーバーが実行モードであるかどうか、およびプラットフォームがターミナル機能をサポートしているかどうかのみをチェックします。validate_auth()を呼び出すことはありません。これらの基本的なチェックを通過すると、接続を受け入れ、完全なPTY(疑似端末)セッションを作成します。```python
async def websocket_connect(self, message): await self.validate_auth() # ✅ Checks authentication await self.accept() # ... notebook communication
async def websocket_connect(self, message): if not self.is_running_mode(): # Only checks mode await self.close() return if not self.is_platform_supported(): # Only checks platform await self.close() return await self.accept() # ❌ No auth! Anyone gets a shell # ... PTY shell creation
これは **CWE-306: 重要な機能に対する認証の欠如** です。サーバー上で最も危険なエンドポイント(対話型シェルを提供するもの)には、認証が一切ありません。
### 攻撃: 3分でAWSキーに到達するアドバイザリ
この悪用のタイムラインは、現代の脅威アクターがどれほど迅速に行動するかを示しています。```
┌──────────────────────────────────────────────────────────────┐
│ CVE-2026-39987 Timeline │
├──────────────────────────────────────────────────────────────┤
│ │
│ T+0h Advisory published │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
│ T+9h First exploit built from advisory │
│ T+10h Exploitation in the wild confirmed │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
│ T+10h 0m Attacker connects to /terminal/ws │
│ T+10h 1m Full PTY shell obtained │
│ T+10h 2m .env file located and read │
│ T+10h 3m AWS keys exfiltrated │
│ Total attack time: ~3 minutes │
└──────────────────────────────────────────────────────────────┘
攻撃自体は極めて単純です:``` Step 1: Attacker opens WebSocket connection to /terminal/ws (No authentication needed, no special tools required)
Step 2: Server creates a PTY (pseudo-terminal) session Attacker now has an interactive shell
Step 3: Attacker runs commands: $ cat .env AWS_ACCESS_KEY_ID=AKIA... AWS_SECRET_ACCESS_KEY=... DATABASE_URL=postgres://... OPENAI_API_KEY=sk-...
Step 4: Credentials exfiltrated Attacker now has cloud access, database access, and API keys for AI services
Total time: under 3 minutes Authentication required: none Tools required: any WebSocket client
No exploit development needed. No shellcode. No memory corruption. Just a WebSocket client and a missing auth check.
---
## Impact Analysis
**Immediate impact on the Marimo host:**
- Full interactive shell with the privileges of the Marimo process
- Access to all files readable by the process (source code, data, credentials)
- Access to environment variables containing API keys and secrets
- Ability to execute arbitrary commands on the host system
**Credential exposure (the primary attack goal):**
- AWS access keys and secret keys from `.env` files or environment variables
- GCP/Azure service account credentials
- Database connection strings with passwords
- OpenAI, Anthropic, and other AI service API keys
- SSH keys and other authentication material
**Downstream impact (via stolen credentials):**
- Unauthorized access to cloud infrastructure (EC2, S3, Lambda, etc.)
- Data exfiltration from cloud storage and databases
- Resource abuse (cryptomining, AI API credit theft)
- Lateral movement into cloud and on-premise networks
**Risk amplification factors:**
- Notebook environments are designed to execute arbitrary code (that's their purpose)
- Data science environments typically have broad cloud access for training jobs
- Many Marimo instances are exposed to the internet for collaboration and remote work
- Security hardening is often an afterthought in research/experimentation environments
---
## Affected Versions
| Version | Status |
|---------|--------|
| Marimo 0.23.0+ | **Patched** |
| Marimo 0.20.5 to 0.22.x | **Likely vulnerable** (between advisory range and fix) |
| Marimo <= 0.20.4 | **Vulnerable** (confirmed range) |
---
## The Bigger Picture: AI/ML Toolchain Under Attack
CVE-2026-39987 is not an isolated incident. It's part of a clear pattern that emerged in April 2026:
| CVE | Product | Type | Status |
|:---|:---|:---|:---|
| **CVE-2026-39987** | Marimo | Pre-Auth RCE (WebSocket) | Exploited in 10 hours |
| **CVE-2026-33017** | Langflow | RCE | CISA KEV (March 26) |
| **CVE-2026-5059** | aws-mcp-server | Command Injection RCE | Public advisory |
| **TorchGeo** | TorchGeo | eval() RCE | Public advisory |
Four AI/ML development tools hit with critical RCE vulnerabilities in a single month. The AI/ML development pipeline is becoming the new shadow IT: tools deployed with broad access, minimal security oversight, and rich credential stores.```
┌─────────────────────────────────────────────────┐
│ Why AI/ML Tools Are Prime Targets │
├─────────────────────────────────────────────────┤
│ │
│ 1. DESIGNED to execute arbitrary code │
│ (that's literally what notebooks do) │
│ │
│ 2. Run with elevated privileges │
│ (GPU access, cloud SDKs, network access) │
│ │
│ 3. Contain high-value credentials │
│ (AWS keys, API tokens, DB connections) │
│ │
│ 4. Often exposed to the network │
│ (for collaboration and remote access) │
│ │
│ 5. Security hardening is an afterthought │
│ (focus on features and UX, not security) │
│ │
│ 6. Users are researchers, not security experts │
│ (default configs, weak passwords, no VPN) │
└─────────────────────────────────────────────────┘
このPythonスクリプトは、多段階の分析を通じて脆弱なMarimoインスタンスを検出します。
動作の仕組み:
/api/status、/api/health、/ にクエリを送信し、レスポンスのコンテンツとヘッダーからMarimoの指標を探します/terminal/ws に対して安全なHTTPアップグレードリクエストを送信します(接続を通じてデータは送信されません)/terminal/ws(認証が必要なはず)と /ws(認証が必要と判明済み)の動作を比較し、不整合を確認しますターゲットシステム上でコマンドが実行されることはありません。 WebSocketハンドシェイクはテストされますが、接続を通じてデータは送信されません。このチェックは完全に受動的であり、本番環境にとって安全です。
使用方法:```bash
pip install -r requirements.txt
python CVE-2026-39987_Marimo_RCE_detector.py -t http://marimo-host:2718
python CVE-2026-39987_Marimo_RCE_detector.py -t https://marimo-host:443
python CVE-2026-39987_Marimo_RCE_detector.py -f targets.txt -o results.json -v
python CVE-2026-39987_Marimo_RCE_detector.py -t http://10.0.0.5:2718 --timeout 15
**オプション:**
| フラグ | 説明 | デフォルト |
|------|-------------|---------|
| `-t`, `--target` | 単一のターゲットURL(例: `http://host:2718`) | — |
| `-f`, `--file` | ターゲットURLを1行に1つずつ含むファイル(`#`コメント対応) | — |
| `-o`, `--output` | 結果をJSONファイルに保存 | — |
| `--timeout` | 接続タイムアウト(秒) | `10` |
| `--verify-ssl` | SSL証明書の検証を有効化 | 無効 |
| `-v`, `--verbose` | 詳細情報を含む冗長出力 | オフ |
**出力例:**```
[*] CVE-2026-39987 Marimo Pre-Auth RCE Scanner
[*] Scanning 1 target(s)...
[*] NOTE: This scanner only checks for endpoint exposure.
[*] No commands are executed on target systems.
======================================================================
Target: http://10.0.0.5:2718
Scan Time: 2026-04-14T16:00:00Z
Risk Level: CRITICAL
======================================================================
Is Marimo: YES
Marimo Version: 0.19.2
/terminal/ws Open: YES — UNAUTHENTICATED
Vulnerable: YES
*** CRITICAL: Pre-authenticated RCE is possible! ***
*** An attacker can get a full PTY shell without any auth ***
Details:
- Marimo instance detected via /api/status
- Marimo version: 0.19.2
- WebSocket upgrade accepted — /terminal/ws accessible WITHOUT auth
- CONFIRMED: /terminal/ws accepts unauthenticated connections while
/ws requires auth — classic CVE-2026-39987 signature
- Version 0.19.2 <= 0.20.4 — VULNERABLE to pre-auth RCE
======================================================================
[*] Scan Complete: 1 targets scanned
[*] Marimo Instances: 1 | Vulnerable: 1 | Critical: 1
======================================================================
sudo cp CVE-2026-39987_Marimo_RCE.nse /usr/share/nmap/scripts/ sudo nmap --script-updatedb
nmap -p 2718 --script CVE-2026-39987_Marimo_RCE
nmap -p 2718,8080,8443,443 --script CVE-2026-39987_Marimo_RCE
nmap -p 2718 --script CVE-2026-39987_Marimo_RCE 10.0.0.0/24
nmap -p 2718 --script CVE-2026-39987_Marimo_RCE -iL targets.txt
nmap -sV -p 2718 --script CVE-2026-39987_Marimo_RCE
**Nmap出力の例:**```
PORT STATE SERVICE
2718/tcp open http
| CVE-2026-39987_Marimo_RCE:
| VULNERABLE:
| Marimo Pre-Auth RCE (CVE-2026-39987)
| State: VULNERABLE
| Risk level: CRITICAL
| Marimo Version: 0.19.2
| /terminal/ws: accessible without authentication
| Description:
| The Marimo /terminal/ws WebSocket endpoint accepts connections
| without authentication, enabling pre-authenticated RCE.
| An attacker can obtain a full PTY shell without any credentials.
| References:
|_ https://nvd.nist.gov/vuln/detail/CVE-2026-39987
Marimo インスタンスにアクセスできる場合:```bash
curl -s http://:2718/api/status | python3 -m json.tool
curl -s -o /dev/null -w "%{http_code}"
-H "Upgrade: websocket"
-H "Connection: Upgrade"
-H "Sec-WebSocket-Key: dGVzdC1rZXktMTIzNDU2Nzg="
-H "Sec-WebSocket-Version: 13"
http://:2718/terminal/ws
curl -s -o /dev/null -w "%{http_code}"
-H "Upgrade: websocket"
-H "Connection: Upgrade"
-H "Sec-WebSocket-Key: dGVzdC1rZXktMTIzNDU2Nzg="
-H "Sec-WebSocket-Version: 13"
http://:2718/ws
`/terminal/ws` が 101 を返し、`/ws` が 401/403 を返す場合、これは典型的な CVE-2026-39987 のシグネチャです。
---
## 侵害の指標
環境内で以下の兆候に注意してください:
| 指標 | 確認場所 | 確認すべき内容 |
|:---|:---|:---|
| 不正な WebSocket 接続 | サーバー/プロキシログ | 予期しない IP からの `/terminal/ws` への接続 |
| PTY セッションの作成 | プロセス監視 | Marimo サーバーによって生成された予期しないシェルプロセス |
| ファイルアクセス | ファイル監査ログ | `.env`、資格情報ファイル、または SSH キーの読み取り |
| 資格情報の使用 | クラウドプロバイダーの監査ログ | Marimo 環境に保存されていたキーを使用した API 呼び出し |
| 外部へのデータ転送 | ネットワーク監視 | Marimo ホストからの異常な送信トラフィック |
**調査コマンド:**```bash
# Check for active WebSocket connections
ss -tnp | grep <MARIMO_PORT>
# Review process tree for unexpected shells
ps aux --forest | grep -A5 marimo
# Check if .env or credential files were recently accessed
stat .env
stat ~/.aws/credentials
# Review cloud provider activity logs for unauthorized access
aws cloudtrail lookup-events --lookup-attributes AttributeKey=AccessKeyId,AttributeValue=<KEY_ID>
# Check for unauthorized outbound connections
netstat -tnp | grep ESTABLISHED | grep -v 127.0.0.1
直ちに実施すべき対応(今すぐ行うこと):
pip install --upgrade marimo)短期対応(今週中):
.env ファイルと環境変数を確認し、漏えいした可能性のある機密データがないか調べる長期的な対策:
Kerem Oruç — サイバーセキュリティエンジニア