
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