FlawOpen

flawopen.com/AI Security/mlflow-webhook-ssrf-cve-2026-64849

● CVE-2026-64849 · CVSS 8.6 · Tinggi
Riset Keamanan · FlawOpen

CVE-2026-64849: SSRF Webhook MLflow

CVE-2026-64849 adalah server-side request forgery (SSRF) tanpa autentikasi pada pengiriman webhook MLflow (tinggi, CVSS 3.1: 8.6). Pemeriksaan URL awal tidak membatasi tujuan redirect atau alamat koneksi sebenarnya; endpoint pengujian dapat mengembalikan isi respons upstream kepada pemanggil.[1]

💡 Penjelasan Sederhana (ELI5)

Bayangkan petugas penerima memeriksa alamat pada paket, tetapi membiarkan kurir mengikuti catatan pengalihan tanpa memeriksa alamat baru. MLflow memeriksa URL webhook sebelum terhubung, tetapi redirect dan pencarian DNS kedua dapat mengirim permintaan ke tempat lain. Perbaikan memeriksa alamat peer yang benar-benar terhubung sebelum mengirim data HTTP.[1], [2]

Konsep Kunci & Istilah

SSRF
Server melakukan permintaan jaringan yang dipilih pemanggil sehingga melintasi batas kepercayaan jaringan server.[1]
Endpoint uji webhook
API MLflow yang mengirim peristiwa uji ke webhook terkonfigurasi; server default terdampak mengembalikan isi respons upstream.[1]
DNS rebinding / TOCTOU
Hostname mengarah ke IP publik saat validasi, tetapi ke alamat nonpublik lain ketika koneksi dibuat.[1], [2]

Pemetaan kerangka kerja

Alur Serangan Langkah demi Langkah

Langkah 1

Server MLflow yang dapat dijangkau menerima uji webhook

Advisory menjelaskan Tracking Server default tanpa autentikasi. Plugin autentikasi dan kontrol deployment dapat mengubah keterjangkauan; periksa konfigurasi aktual. CISA menambahkan CVE ini ke katalog Known Exploited Vulnerabilities pada 19 Agustus 2026; pencantuman menunjukkan eksploitasi yang diketahui, tetapi tidak membuktikan kompromi pada deployment tertentu.[1], [4], [5]

Langkah 2

URL awal lolos validasi

_validate_webhook_url menyelesaikan dan memeriksa hostname awal, tetapi alamat yang diperiksa dibuang dan tidak diikat ke socket berikutnya.[1]

Langkah 3

Redirect atau resolusi ulang mencapai tujuan lain

Klien HTTP mengikuti redirect dan koneksi dapat menyelesaikan hostname lagi. Endpoint uji memantulkan isi respons upstream sehingga SSRF dapat membaca respons penuh.[1]

Langkah 4

Perbaikan upstream memeriksa peer yang terhubung

PR #24258 memvalidasi peer socket tepat setelah koneksi dan sebelum data TLS/HTTP; sesi juga menghindari proxy lingkungan. MLflow 3.15.0 memperbaiki CVE ini; bypass transisi IPv6 yang terpisah diperbaiki pada 3.16.0. Advisory tersebut mencantumkan freeman-bb sebagai pelapor privat pertama dan AUTHENSOR sebagai penemu independen.[1], [2], [3], [6]

Kode Sumber: Rentan vs Aman

Cuplikan menunjukkan batas antara validasi URL dan permintaan aktual serta pemeriksaan peer saat koneksi. Permintaan eksploit dan tujuan internal dihilangkan. Normalisasi IPv6 di 3.16.0 adalah hardening lanjutan yang terpisah.[2]

IMPLEMENTASI RENTAN
# PR #24258 sebelum diterapkan, dari 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
PERBAIKAN AMAN & KUAT
# Cuplikan perbaikan upstream yang memeriksa peer saat koneksi dibuat.
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)

Daftar Periksa Penguatan Sistem Rekayasa

Sumber

← AI Security Directory →