flawopen.com/AI Security/mlflow-webhook-ssrf-cve-2026-64849
●
CVE-2026-64849 · CVSS 8.6 · 高
セキュリティ研究 · FlawOpen
CVE-2026-64849:MLflow WebhookのSSRF脆弱性
CVE-2026-64849は、MLflowのWebhook配信における未認証のサーバーサイドリクエストフォージェリ(SSRF)です (High、CVSS 3.1:8.6)。最初のURL検証ではリダイレクト先や実際の接続先IPが制限されず、テスト用endpointが上流レスポンス本文を呼び出し元へ返す可能性がありました。[1]
💡 わかりやすい解説 (ELI5)
受付担当者が荷物の住所を確認した後、転送メモに書かれた新しい住所を確認せず配達員に進ませる状況を想像してください。MLflowは接続前にWebhook URLを確認しましたが、リダイレクトや再度のDNS検索で別の宛先へ接続する可能性がありました。修正ではHTTPデータを送る前に実際の接続先peerを検査します。[1], [2]
主要な概念と専門用語
SSRF- 呼び出し元が選んだネットワーク要求をサーバーが実行し、サーバーのネットワーク信頼境界を越える問題。[1]
Webhookテストendpoint- 設定済みWebhookへテストイベントを送るMLflow API。影響を受けるデフォルト構成では上流レスポンス本文を返した。[1]
フレームワーク対応
- このガイドで説明する弱点の CWE 参照: CWE-918
- D3-OTF 送信トラフィックのフィルタリング — このガイドで説明する送信ネットワークの制限により、サービスまたはホストが接続できる宛先を絞れます。
- CISA KEV — 追加日 2026-08-19 — CVE-2026-64849
ステップ・バイ・ステップの攻撃フロー
ソースコード比較:脆弱 vs 堅牢化
コード断片はURL検証と実際の要求の境界、接続時のpeer検証を示します。悪用要求や内部宛先は含みません。3.16.0のIPv6正規化は後続の独立した強化です。[2]
脆弱な実装
# PR #24258 適用前の mlflow/webhooks/delivery.py の抜粋。
_validate_webhook_url(webhook.url) # checks the initial URL only
return session.post(
webhook.url, data=payload_bytes, headers=headers, timeout=timeout
) # redirects follow by default; the validated IP is not pinned
堅牢化されたセキュアパッチ
# 接続時に接続先ピアを検証する upstream 修正の抜粋。
def _assert_public_peer(sock):
if _MLFLOW_WEBHOOK_ALLOW_PRIVATE_IPS.get():
return
try:
peer_ip = sock.getpeername()[0]
except OSError as exc:
sock.close()
raise SSRFProtectionError(
f"Could not determine webhook connection peer address: {exc}"
) from exc
try:
ip = ipaddress.ip_address(peer_ip)
except ValueError as exc:
sock.close()
raise SSRFProtectionError(
f"Webhook connection resolved to an invalid IP address: {peer_ip!r}"
) from exc
if not ip.is_global:
sock.close()
raise SSRFProtectionError(
f"Webhook connection blocked: {ip} is not a public IP address. "
"This may indicate a DNS rebinding attempt."
)
class _SSRFProtectedHTTPConnection(HTTPConnection):
def _new_conn(self):
sock = super()._new_conn()
_assert_public_peer(sock)
return sock
class _SSRFProtectedHTTPSConnection(HTTPSConnection):
def _new_conn(self):
sock = super()._new_conn()
_assert_public_peer(sock)
return sock
adapter = SSRFProtectedHTTPAdapter(max_retries=retry_strategy)
session = requests.Session()
session.trust_env = False
session.mount("http://", adapter)
session.mount("https://", adapter)
エンジニアリング&システム堅牢化チェックリスト
- ✓CVE-2026-64849についてMLflow 3.10.0–3.14.xを少なくとも3.15.0へ更新し、現在サポート中の版を優先します。IPv6移行機構がある環境では後続修正を含む3.16.0以降を導入します。[1], [3], [6]
- ✓Tracking Serverが未信頼ネットワークから到達できないか確認し、任意の認証プラグインと認可確認の有効状態を調べます。ネットワーク制限は更新の代替ではなく多層防御です。[1]
- ✓サーバーの外向き通信を必要な宛先に限定し、loopback、link-local、プライベート範囲、クラウドメタデータをネットワーク層で遮断します。外向き取得コードでは各リダイレクトと接続peerを再検証します。 本番環境では
MLFLOW_WEBHOOK_ALLOW_PRIVATE_IPSを無効に保ち、必要な場合も隔離された開発環境だけで有効にしてください。[2], [7] - ✓CI回帰テストで、非公開アドレスへの直接接続、リダイレクト先、DNS rebinding、HTTP/HTTPSプール、プロキシ経由の接続が要求データ送信前に拒否されることを確認し、プライベートIP許可の例外も個別にテストしてください。[2], [7]