flawopen.com/AI Security/mlflow-webhook-ssrf-cve-2026-64849
CVE-2026-64849: MLflow-Webhook-SSRF
CVE-2026-64849 ist eine unauthentifizierte serverseitige Anforderungsfälschung (SSRF) bei der MLflow-Webhook-Zustellung (hoch, CVSS 3.1: 8.6). Die Prüfung der ursprünglichen URL begrenzte weder Weiterleitungsziele noch die Adresse der tatsächlichen Verbindung; der Test-Endpunkt konnte den Antworttext des Ziels zurückgeben.[1]
Stellen Sie sich einen Empfang vor, der die Paketadresse prüft, den Zusteller aber einer Weiterleitungsnotiz folgen lässt, ohne das neue Ziel zu kontrollieren. MLflow prüfte die Webhook-URL vor dem Verbindungsaufbau; Weiterleitungen und eine zweite DNS-Abfrage konnten die Anfrage dennoch woandershin leiten. Die Korrektur prüft die Adresse des tatsächlich verbundenen Peers, bevor HTTP-Daten gesendet werden.[1], [2]
Kernkonzepte & Begriffe
SSRF- Der Server führt eine vom Aufrufer gewählte Netzwerkanfrage aus und überschreitet damit seine Netzwerk-Vertrauensgrenze.[1]
Webhook-Test-Endpunkt- MLflow-API, die ein Testereignis an einen konfigurierten Webhook sendet; betroffene Standardserver gaben den Antworttext des Ziels zurück.[1]
Framework-Zuordnungen
- CWE-Referenz für die in diesem Leitfaden beschriebene Schwachstelle: CWE-918
- D3-OTF Filterung des ausgehenden Datenverkehrs — Die in diesem Leitfaden beschriebene Beschränkung des ausgehenden Netzwerkverkehrs begrenzt die für den Dienst oder Host erreichbaren Ziele.
- CISA KEV — aufgenommen am 2026-08-19 — CVE-2026-64849
Schritt-für-Schritt Angriffsablauf
Ein erreichbarer MLflow-Server nimmt einen Webhook-Test an
Der Hinweis beschreibt einen nicht authentifizierten Tracking Server in der Standardkonfiguration. Authentifizierungs-Plugins und Bereitstellungskontrollen ändern die Erreichbarkeit; prüfen Sie die tatsächliche Konfiguration. CISA nahm die CVE am 19. August 2026 in den Katalog Known Exploited Vulnerabilities auf. Das weist auf bekannte Ausnutzung hin, belegt aber keine Kompromittierung einer bestimmten Installation.[1], [4], [5]
Die erste URL besteht die Prüfung
_validate_webhook_url löst den ursprünglichen Hostnamen auf und prüft ihn, verwirft die geprüfte Adresse jedoch, statt sie an den späteren Socket zu binden.[1]
Weiterleitung oder erneute Auflösung erreicht ein anderes Ziel
Der HTTP-Client folgt Weiterleitungen; die Verbindung kann den Hostnamen erneut auflösen. Der Test-Endpunkt spiegelte den Antworttext zurück und ermöglichte damit SSRF mit vollständiger Antwortlesbarkeit.[1]
Der Upstream-Fix prüft den verbundenen Peer
PR #24258 prüft die Socket-Peer-Adresse direkt nach dem Verbindungsaufbau und vor TLS/HTTP-Daten; die Sitzung umgeht außerdem Umgebungs-Proxys. MLflow 3.15.0 behebt die CVE; separate IPv6-Übergangs-Umgehungen sind in 3.16.0 behoben. Die Meldung nennt freeman-bb als ursprünglichen vertraulichen Melder und AUTHENSOR als unabhängigen Finder.[1], [2], [3], [6]
Quellcode: Verwundbar vs. Sicher
Die Auszüge zeigen die ursprüngliche Grenze zwischen URL-Prüfung und Anfrage sowie die Upstream-Prüfung des Peers beim Verbindungsaufbau. Exploit-Anfragen und interne Ziele fehlen. Die IPv6-Normalisierung in 3.16.0 ist eine spätere, separate Härtung.[2]
# Auszug aus mlflow/webhooks/delivery.py vor PR #24258.
_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
# Auszug aus dem Upstream-Fix mit Prüfung des Peers beim Verbindungsaufbau.
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)
Checkliste für Engineering & Systemsicherheit
- ✓Aktualisieren Sie MLflow 3.10.0–3.14.x für
CVE-2026-64849mindestens auf 3.15.0; bevorzugen Sie einen aktuell unterstützten Stand. Bei IPv6-Übergangsmechanismen 3.16.0 oder neuer einsetzen.[1], [3], [6] - ✓Stellen Sie fest, ob der Tracking Server aus nicht vertrauenswürdigen Netzen erreichbar ist und ob das optionale Authentifizierungs-Plugin sowie Autorisierungsprüfungen aktiv sind. Netzwerkfilter ergänzen das Update, ersetzen es aber nicht.[1]
- ✓Begrenzen Sie ausgehenden Serververkehr auf nötige Ziele und blockieren Sie Loopback, Link-Local, private Netze und Cloud-Metadaten. Prüfen Sie jede Weiterleitung und den verbundenen Peer im ausgehenden Abrufcode erneut. Lassen Sie
MLFLOW_WEBHOOK_ALLOW_PRIVATE_IPSin der Produktion deaktiviert; aktivieren Sie die Option nur bei ausdrücklichem Bedarf in isolierten Entwicklungsumgebungen.[2], [7] - ✓Ergänzen Sie CI-Regressionstests, die direkte nicht öffentliche Adressen, Weiterleitungsziele, DNS-Rebinding, HTTP/HTTPS-Pools und Proxy-Routen vor dem Senden von Anfragedaten blockieren; testen Sie die Ausnahme für private IPs separat.[2], [7]