← すべての記事

ループバックは信頼境界ではない:CVE-2026-2611

From the guide: Claude Code Comprehensive Guide

2026年5月19日、National Vulnerability DatabaseはCVE-2026-2611を公開しました。MLflow 3.9.0のAssistant機能では、ローカルの/ajax-apiエンドポイントに対するOrigin検証が不適切でした。任意のタブで読み込まれた悪意あるWebページがAssistantのローカルサーバーへクロスオリジンリクエストを送り、設定を変更してフルアクセスモードを有効にし、同梱されたClaude Code CLI連携を通じて任意のコマンドを実行できる状態でした。Huntrはこの脆弱性にCVSS 3.0で9.6(CRITICAL)を付けています。ベクトルはAV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:Hで、ネットワークから到達可能、攻撃の複雑さは低い、権限は不要、スコープ変更あり、機密性・完全性・可用性のすべてに高い影響がある、という評価です。1

根本原因は新しいものではなく、修正も特殊ではありません。ただし脅威モデルは新しくなっています。 ループバックにバインドし、ブラウザータブに変更系エンドポイントを公開するローカルサービスは、信頼境界の表面になります。そのサービスが、ファイルを読み、シェルコマンドを実行し、コードをプッシュできるAIエージェントを動かしているなら、「ループバックだけ」という条件はセキュリティ制御として機能しません。CVE-2026-2611は、今後さらに多くの開発者ツールがローカルWeb UIの中にLLMエージェントを組み込むにつれて、繰り返し発生する脆弱性クラスの教科書的な事例です。

要約

CVE-2026-2611は、MLflow 3.9.0における不完全なCORS対象列挙のバグです。Assistant機能は/ajax-api/エンドポイントを公開していましたが、MLflowのis_api_endpoint()チェックはそこを対象にしていませんでした。その結果、CORSブロック用ミドルウェアがそれらのパスを素通ししていました。さらに従来のCORSMiddlewareではallow_origins=["*"]が許可されていたため、evil.comからのクロスオリジンリクエストが/ajax-api/3.0/mlflow/assistant/configを呼び出し、Assistantをフルアクセスモードに切り替え、同梱されたClaude Code CLI連携を通じてシェルコマンドを送れる状態でした。1 MLflow 3.10.0に入った上流修正(PR #20832「Block CORS for ajax paths」)では、保護対象パスの列挙に/ajax-api/を追加し、allow_originsを設定済みの許可リストとlocalhost正規表現に絞っています。2 以下の防御策はMLflowだけでなく、ローカルAIエージェント全体のクラスを対象にしています。

重要ポイント

立場 対応
MLflowを動かしているAI/MLエンジニア MLflow 3.10.0へアップグレードし、ループバックで待ち受ける他のローカルAIエージェントUIも監査してください
セキュリティチーム 脅威モデルのテンプレートに「ローカルLLMエージェントのループバックサービス」を追加してください。このクラスでは、CORSの抜け1つが任意コード実行につながります
ローカルエージェントUIを作るツール作者 APIのパスプレフィックスは1か所で網羅してください。localhostにバインドしたサーバーでもallow_origins=["*"]は禁止です。破壊的エンドポイントはOriginだけでなく、新しいユーザー操作で保護してください
エンジニアリングリード チームのAIコーディングエージェントをサンドボックス化し、そのコマンド実行能力を実際の影響範囲として扱ってください

攻撃チェーンの流れ

5ステップの短いチェーンです。各ステップは認可済みの機能を使っています。壊れているのは、その組み合わせです。

ステップ 操作 攻撃者が制御するもの
1 ユーザーがローカルでmlflow uiを実行し、Assistantがループバック(デフォルトは127.0.0.1)で待ち受ける まだ何もありません(ローカルサービス)
2 MLflow実行中に、ユーザーが任意のタブでevil.comを開く ページ内容
3 evil.comfetch('http://127.0.0.1:5000/ajax-api/3.0/mlflow/assistant/config', { method: 'PUT', credentials: 'include', body: ... })を送る クロスオリジンリクエスト
4 /ajax-api/がCORSブロック対象のパス列挙に入っていなかったため、MLflowがリクエストを受け入れる。Assistant設定がフルアクセスに切り替わる Assistantの実行時設定
5 evil.comがAssistantのチャットエンドポイント経由でコマンドペイロードを投稿する。MLflowは権限チェックを迂回した状態でローカルのClaude Code CLIを呼び出し、ユーザー権限でコマンドが実行される 任意コード実行

攻撃者は被害者のマシンに何かをインストールする必要がありません。必要なのは、mlflow uiが動いている間に、ペイロードを含むタブを1つ読み込ませることだけです。従来のCORSMiddlewareallow_origins=["*"]があり、さらにパス単位のCORSブロックミドルウェアが/ajax-api/プレフィックスを対象にしていなかったため、この攻撃はどのOriginからでも成立します。2

Claude Code連携は権限の増幅器です。MLflowのClaudeCodeProvidershutil.which("claude")でローカルのclaude CLIを探し、見つからない場合はnpm install -g @anthropic-ai/claude-codeでインストールするよう案内します。Assistantのpermissions.full_access設定フラグが有効な場合、プロバイダーはCLI呼び出しに--permission-mode bypassPermissionsを追加します。これはClaude Codeのモードで、対話的な権限確認を抑制し、ユーザー確認なしでツール呼び出しを実行できるようにします。3 エージェントに許可された機能(シェル、ファイル書き込み、HTTP)が、自然言語UX付きのリモートシェルになります。攻撃者にとってはまさに欲しいものです。


根本原因は不完全なパス列挙です

修正コミットを読むと、バグは明白です。MLflowのsecurity_utils.pyには、次の定数がありました。

API_PATH_PREFIX = "/api/"

そして、次のチェックがありました。

def is_api_endpoint(path: str) -> bool:
    return path.startswith(API_PATH_PREFIX) and path not in TEST_ENDPOINTS

CORSブロック用ミドルウェアは、Origin検証を適用するかどうかをis_api_endpoint()で判断していました。/api/で始まらないパスは、非APIパスとして扱われていました。Assistantはブラウザー向けエンドポイントとして/ajax-api/を導入しましたが、is_api_endpoint()に新しいプレフィックスを含める更新が行われていませんでした。

修正はsecurity_utils.pyにおける1行相当の挙動変更です。2

API_PATH_PREFIX = "/api/"
AJAX_API_PATH_PREFIX = "/ajax-api/"

def is_api_endpoint(path: str) -> bool:
    return (
        path.startswith(API_PATH_PREFIX) or path.startswith(AJAX_API_PATH_PREFIX)
    ) and path not in TEST_ENDPOINTS

加えて、fastapi_security.pyでも並行して修正され、従来のCORSMiddlewareにあったallow_origins=["*"]が、設定済みの許可リストとlocalhost正規表現に置き換えられました。変更全体は、security_utils.pyで5行追加・2行削除、fastapi_security.pyで5行追加・1行削除です。2

脆弱性の本体はこれだけです。CVE-2026-2611は、新しいエンドポイントプレフィックスが追加されたにもかかわらず、CORS保護対象のパスを列挙する1つの関数が更新されなかったために発生しました。攻撃対象領域は、忘れられた設定定数でした。

なぜこのパターンは繰り返されるのか

このバグはMLflowよりも古く、AIエージェントよりも古いものです。Webフレームワークでは、パス列挙が存在する限り、パス列挙ミスも出荷されてきました。変わったのは結果です。ローカルWeb UIがエンドポイントを1つ列挙し忘れても、以前なら設定データが少し漏れるか、サービス拒否を引き起こす程度でした。シェルアクセスを持つAIコーディングエージェントを動かしているローカルWeb UIで同じ忘れ方をすると、開発者マシン全体が漏れます。

ローカルAIエージェントUIは拡大中のカテゴリです。127.0.0.1から配信されるブラウザーUIの中にLLMエージェントを組み込むツールは、どれも対象になります。チャットパネルを持つ実験トラッカー(MLflow型)、localhost API経由でエージェントを動かすIDEプラグイン、拡張機能がHTTPでやり取りする開発モードのサーバー、ローカルモデルランナー用のWebダッシュボード。どれもループバックにバインドします。どれもブラウザータブに変更系エンドポイントを公開します。どれもシェル実行、ファイル書き込み、gitへのプッシュを許されたエージェントを動かします。そして、どれもパス列挙のバグ1つでCVE-2026-2611と同じ場所に立ちます。

このクラスの根底にある共通の前提は、「正当なリクエストも127.0.0.1から来るので、ブラウザーの同一オリジンポリシーがループバックサーバーを守ってくれる」というものです。この前提は、クロスオリジンの関門(CORS、Hostヘッダー検証、Originヘッダー検証、Fetch Metadataヘッダー)のどれかがエンドポイントプレフィックスを見落とした瞬間に崩れます。サーバーが明示的にリクエストを受け入れるなら、ブラウザーはサーバーを守りません。

3月に取り上げた静かな外向き通信攻撃は、同じ信頼前提が逆方向に壊れたものです。静かな外向き通信では、エージェントに許可されたツールを通じて出口が隠れます。ループバックの誤分類では、ブラウザーに許可されたネットワーク呼び出しを通じて入口が隠れます。どちらも結局は同じです。境界チェックが1つ破れるだけで、LLMエージェントに許可された機能が攻撃手段になります。

このクラスの実体

この脆弱性クラスには4つの要素があります。4つすべてがそろうと、サービスは悪用可能になります。

  1. ループバックまたは0.0.0.0にバインドされたローカルWebサーバー。 よくあるのはループバック限定の形です。localhostにバインドされたサービスをクロスオリジンタブから守るのは、ネットワークバインドではなく、ブラウザーのCORS、Host、Originチェックです。
  2. ユーザー操作なしで到達できる変更系エンドポイント。 設定変更、コマンド送信、ファイル書き込み。任意のOriginからのfetch()で状態を変更できるなら、そのサービスには到達できます。
  3. ローカルユーザーは持っているが、Webページが持つべきではない能力。 ホームディレクトリの読み取り、シェルコマンド実行、保存済み認証情報を使ったクラウドAPI呼び出し、ソースファイルの変更などです。
  4. 境界チェックの抜けが1つあること。 忘れられたパスプレフィックス、ワイルドカードのallow_origins、Hostヘッダー検証漏れ、Origin検証漏れ、Sec-Fetch-Site強制の欠落。

CVE-2026-2611は4つすべてに該当しました。修正はMLflowの/ajax-api/プレフィックスについて、4つ目の要素を閉じています。しかし1つ目から3つ目は、他のあらゆるローカルAIエージェントツールにも残っています。このクラスの次のCVEは、パッケージ名が違うだけで同じ形になるでしょう。


ローカルAIエージェントのループバッククラスに対する防御

標準的なCORS対策(allow_originsを具体的なリストにする、必要な場合だけcredentialsを有効にする)は必要ですが、それだけでは足りません。このクラスには、より深い制御が必要です。

パスプレフィックスは1か所で列挙し、新しいプレフィックスが保護されていない場合に失敗するテストを書いてください。 MLflowのバグは、/api/が出荷されたときにはis_api_endpoint()を更新したのに、/ajax-api/が出荷されたときには忘れたことで入りました。FastAPIアプリに登録された全ルートを反復し、各ルートが保護対象かどうかをis_api_endpoint()に問い合わせ、認識されないパスプレフィックスがあれば失敗するテストがあれば、PR時点で捕捉できていたはずです。このチェックは20行程度のテストコードで済みます。

CORSだけでなく、OriginヘッダーとHostヘッダーを検証してください。 CORSが守るのは、ブラウザーがサーバーのレスポンスを読むことです。サーバーがリクエストを受け入れること自体は守りません。ローカルAIエージェントサービスは、Originヘッダーが明示的な許可リストに含まれていないリクエスト、またHostヘッダーが127.0.0.1またはlocalhostでないリクエストを拒否すべきです。後者はDNSリバインディング攻撃を防ぐためでもあります。どちらのチェックも、迷ったら拒否する設計にしてください。

破壊的エンドポイントはSec-Fetch-Site: same-originで保護してください。 ブラウザーは、evil.comから127.0.0.1へのものを含め、クロスオリジンのfetch()Sec-Fetch-Site: cross-siteを送ります。Fetch Metadata Request Headers仕様はこのヘッダー値を定義しており、Chrome、Firefox、Safari、Edgeはいずれも送信します。4 変更系エンドポイントへのリクエストについて、Sec-Fetch-Site: same-originでないものを拒否するミドルウェアを置けば、すべてのパスプレフィックスを覚えておくことに依存しない追加レイヤーになります。

AIエージェントの実行能力をサンドボックス化してください。 Claude Code、Cursor、Aider、Continueはいずれも、デフォルトではユーザーの全権限で動きます。その方がUXとして最も簡単だからです。ワークスペースごとの能力制限環境(Linuxなら明示的なマウントルール付きのbwrap.appバンドルとして出荷するツールならmacOSのアプリ用サンドボックス機構、クロスプラットフォームならワークスペースごとのコンテナ)を使うと、主要な作業の流れを犠牲にせずに影響範囲を縮小できます。この緩和策は摩擦を増やします。その摩擦こそが目的です。

エージェントのコミットは、レビューされるまで信頼しないでください。 ブランチ保護、必須レビュー、署名付きコミットが必要です。「コミット権限を持つAIエージェント」モデルは、攻撃者がエージェントのローカル環境を侵害した瞬間に崩れます。AIコードレビューには異議が必要ですで扱ったレビュー担当者の異議は、ここにも当てはまります。AIエージェントと人間のレビュー担当者が常に同意するなら、その人間のレビュー担当者は飾りです。


このクラスの次のCVEはどう見えるか

面白い問いは、CVE-2026-2611型の次の脆弱性が出るかどうかではありません。どのパッケージが先に出荷するかです。候補は、ローカルAIツールのエコシステム全体にあります。エージェントをUIに組み込む実験トラッカー、HTTP経由でローカルのエージェントバックエンドと話すIDEプラグイン、作業中に何らかのツールが開く開発モードのサーバー、エージェントUIを動かすために拡張機能が使うlocalhost API。この形でCVEを公開したものは、まだありません。しかしそのいくつかは、ループバックにバインドし、ブラウザーを信頼の関門としてクロスオリジンリクエストを受け入れるコードパスを出荷しています。

このクラスはCVE-2026-2611より大きく、脅威モデルは変わりました。2026年の開発者マシンには、シェル実行し、ファイルを書き、コミットをプッシュし、クラウドAPIを呼び出せるAIエージェントが載っています。それらを動かすローカルWeb UIは、UIのHTTPサーバーが強制する信頼境界を通じて、エージェントの権限を継承します。2020年のWebフレームワークにおけるCORS設定ミスは、設定データを少し漏らす程度でした。2026年のローカルAIエージェントUIにおけるCORS設定ミスは、開発者マシン全体と本番デプロイ能力を漏らします。

修正は単なるパッチではありません。修正とは、テスト付きの明示的なパス列挙、多層防御としてのヘッダー検証、能力サンドボックス、そしてエージェントが書いたコミットに対するレビュー規律という制御の組み合わせです。その一部だけを出荷するツールは、プレフィックスだけが違うCVE-2026-2611の後継を出荷することになります。


FAQ

CVE-2026-2611とは何ですか?

CVE-2026-2611は、MLflow 3.9.0のAssistant機能にあった不適切なOrigin検証の欠陥に対するNational Vulnerability Databaseの識別子です。この欠陥により、任意のWebページがAssistantのローカル/ajax-apiエンドポイントへクロスオリジンリクエストを送り、設定を変更してフルアクセスモードを有効化し、同梱されたClaude Code CLI連携を通じて任意のコマンドを実行できます。CVSS 3.0の基本スコアは9.6(CRITICAL)です。MLflow 3.10.0のPR #20832「Block CORS for ajax paths」で修正されました。12

根本原因は何ですか?

MLflowのis_api_endpoint()チェックは、/api/というパスプレフィックスだけを列挙していました。Assistant機能が/ajax-api/エンドポイントを導入したとき、その列挙は更新されませんでした。そのため、CORSブロック用ミドルウェアは/ajax-api/へのクロスオリジンリクエストをOriginチェックなしで通していました。さらに、従来のCORSMiddlewareallow_origins=["*"]を許可していたことも被害を広げました。ブロックされないパスでは、どのOriginに対しても緩いCORSヘッダーを返していたからです。修正では、パスチェックにAJAX_API_PATH_PREFIX = "/ajax-api/"を追加し、allow_origins=["*"]を設定済みの許可リストとlocalhost正規表現に置き換えています。2

自分のMLflowインストールが影響を受けるかどうかは、どう確認できますか?

pip show mlflow | grep Versionを実行してください。NVDのCPE範囲によれば、MLflowのバージョン>=3.9.0,<3.10.0が影響を受けます。MLflow 3.10.0(2026年2月20日リリース)には修正が入っています。pip install --upgrade mlflowでアップグレードし、実行中のmlflow uiプロセスがあれば再起動してください。

Claude Code CLIがインストールされていなくても攻撃は成立しますか?

設定変更の段階は成立します。任意コード実行の段階には、被害者のPATH上にClaude Code CLIが存在する必要があります。MLflowのAssistantはshutil.which("claude")でそれを呼び出すためです。CLIがない場合、最悪ケースは任意コード実行ではなく、情報漏えいと任意の設定改ざんになります。文書化されたAssistantセットアップ手順に従ってClaude Codeバックエンドを設定したユーザーでは、実際の露出は任意コード実行です。

他のローカルAIエージェントサービスはどう守ればよいですか?

4つの要素を監査してください。ループバックまたはワイルドカードのバインド、変更系エンドポイント、エージェントレベルの能力、そして抜けがあり得る境界チェックです。明示的なOrigin許可リスト、127.0.0.1/localhostに対するHostヘッダー検証(DNSリバインディング対策)、破壊的エンドポイントに対するSec-Fetch-Site: same-originの関門を追加します。エージェントの実行能力はbwrap、macOSのアプリ用サンドボックス機構、ワークスペースごとのコンテナでサンドボックス化してください。エージェントのgitコミットは、レビューされるまで信頼しないでください。



  1. National Vulnerability Database. “CVE-2026-2611: MLflow Assistant improper origin validation.” 2026年5月19日公開。CVSS 3.0基本スコア9.6(CRITICAL)、ベクトルCVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H、Huntr発行。修正はMLflow 3.10.0に出荷。https://nvd.nist.gov/vuln/detail/CVE-2026-2611。Original report: https://huntr.com/bounties/8462addd-b464-4a84-b6a2-5529604e6e5a。 

  2. MLflow. “Block CORS for ajax paths (#20832).” 2026年2月16日、Tomu Hirataによりマージ。変更ファイル:mlflow/server/fastapi_security.py(+5/-1)、mlflow/server/security_utils.py(+5/-2)、およびテスト更新。このdiffは、is_api_endpoint()の単一プレフィックスチェックを2つのプレフィックスチェックに置き換え、従来のCORSMiddlewareallow_origins["*"]から設定済みの許可リストとlocalhost正規表現へ絞っています。https://github.com/mlflow/mlflow/commit/8f9c8a53af90842944101eb8b7d60706822c81bc。 

  3. MLflow 3.10.0 source。mlflow/assistant/providers/claude_code.pyshutil.which("claude") lookup(lines 268, 280, 355)、install hint "Install it with: npm install -g @anthropic-ai/claude-code"(line 286)、config.permissions.full_accessにより制御されるpermission-mode escalation cmd.extend(["--permission-mode", "bypassPermissions"])(lines 379–381)。mlflow/assistant/config.pyPermissionsConfig.full_access: bool = False default(line 15)。mlflow/server/assistant/api.py:router prefix /ajax-api/3.0/mlflow/assistant(line 63)、GET /config reader(line 261)、PUT /config mutator(line 276)。このPUT endpointが、cross-origin attackでfull_accessを切り替える標的です。PyPIのMLflow 3.10.0 sdist(mlflow-3.10.0.tar.gz)に対して確認済み。 

  4. W3C. “Fetch Metadata Request Headers.” Sec-Fetch-Siteと、その値であるcross-sitesame-originsame-sitenoneを定義しています。Chrome 76+、Firefox 90+、Safari 16.4+、Edge 79+で実装済み。https://www.w3.org/TR/fetch-metadata/。 

関連記事

メンテナーが攻撃者になるとき:jqwik 1.10.0

jqwik 1.10.0 は、Maven 出力に破壊的なプロンプトインジェクション文字列を出します。ANSI エスケープで人間からは隠されます。メンテナーは意図的に追加しました。

3 分で読める

AIエージェント設定のセキュリティはサプライチェーンのセキュリティです

AIエージェント設定のセキュリティは、サプライチェーンレビューに含めるべき対象です。フック、エディタタスク、インストールスクリプト、MCPファイル、プラグインは、気づく前にコードを実行できるからです。

2 分で読める

Ralphループ:自律型AIエージェントを一晩中稼働させる方法

ストップフック、スポーンバジェット、ファイルシステムメモリを備えた自律エージェントシステムを構築しました。失敗から学んだことと、実際にコードをシップする仕組みを紹介します。

3 分で読める