MLflow SSRF (CVE-2026-64849): a validate-then-fetch bug
CISA added CVE-2026-64849 to its Known Exploited Vulnerabilities catalog on August 19, 2026, giving federal agencies until September 2 to patch it (CISA KEV). The bug: an unauthenticated, CVSS 9.3 server-side request forgery in MLflow, the open-source ML experiment-tracking platform that ships in a lot of AI/ML pipelines running on EC2, GKE, and AKS. Researchers at watchTowr reported scanning for exposed MLflow servers starting within hours of the CVE being assigned (The Hacker News). What makes it worth a closer look isn’t just “another SSRF into cloud metadata” — it’s a textbook case of a security control that exists, looks correct, and still doesn’t work because of the gap between when you check something and when you use it.
Root cause
MLflow lets you register webhooks — URLs it calls when a model is
registered, a run finishes, and so on — and it added an SSRF guard for
exactly the obvious reason: don’t let a webhook URL point at
169.254.169.254 or 127.0.0.1. That guard,
_validate_webhook_url
(shipped in 3.10.0), resolves the hostname you supply and rejects it if
the resolved IP is private, loopback, or link-local. Sound in isolation.
The flaw is in the unauthenticated POST
/api/2.0/mlflow/webhooks/{id}/test endpoint, which validates the URL
and then, in a separate step, actually delivers a request to it —
following HTTP redirects, with the validated IP never pinned to the
connection that follows (GitHub advisory).
That’s a classic time-of-check-to-time-of-use (TOCTOU) bug applied to
network requests instead of a filesystem. Two ways to exploit the gap:
host a public HTTPS endpoint that passes the resolve-and-check step, then
have it respond 302 Location: http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>
— MLflow’s HTTP client happily follows the redirect to the real target
without re-checking it. Or skip the redirect entirely and use DNS
rebinding: register a hostname that resolves to a public IP at
validation time and to 169.254.169.254 a few seconds later when the
actual delivery request does its own, independent DNS lookup. Either
way, the /test endpoint reflects the upstream response — status code
and body — straight back to the caller, so this isn’t blind SSRF. It’s
full-read: whatever comes back from the metadata service is handed to
the attacker verbatim.
Blast radius
No authentication required, and MLflow’s tracking server is routinely
deployed with far looser access controls than a production database,
because it’s “just” an internal ML tool. That combination — internet- or
VPC-reachable, unauthenticated by design in a lot of default configs,
and now capable of full-read SSRF — means an attacker who finds an
exposed instance can request /latest/meta-data/iam/security-credentials/<role-name>
on AWS, the equivalent Azure IMDS token endpoint, or GCP’s metadata
server, and read the response directly out of the webhook-test reply.
From there it’s the same story as every other IMDS-credential-theft
incident: the stolen credentials are indistinguishable from legitimate
ones to anything downstream, and the damage ceiling is set by whatever
IAM role, service account, or managed identity the MLflow host was
running as. Given that ML training and tracking infrastructure often
holds credentials with broad S3/GCS/blob storage access — that’s where
the training data and model artifacts live — the instance role attached
to an MLflow box is a plausible high-value target, not an afterthought.
Remediation
Upgrade to MLflow 3.15.0 or later, which fixes the actual bug: it pins
the validated IP to the connection used for delivery instead of trusting
a fresh DNS lookup or a redirect target
(PR #24258). That’s the
only complete fix — allowlisting webhook domains or blocking
169.254.169.254 at a WAF layer doesn’t address DNS rebinding, since
the rebind happens after any URL-string-based check passes. Two things
to do regardless of patch status. First, MLflow tracking servers should
never be reachable from the public internet or from network paths a
generic tenant workload can reach — treat it like any other internal
admin service with a security boundary, not like a stateless API. Second,
and this is the layer that actually caps the damage from any future
SSRF in any internal tool, not just this one: enforce IMDSv2
(HttpTokens: required) on every instance, since its hop-limited,
token-gated handshake breaks a plain redirect-or-rebind relay the same
way it would have broken the Capital One SSRF path years earlier. Scope
the instance role or service account narrowly, too — MLflow doesn’t need
account-wide storage access to do its job, and a role limited to the
specific artifact buckets it manages turns a successful SSRF into a
contained incident instead of an account-wide one.
Join the discussion
Comments for this post live on social — reply to the thread.
Related posts
Storm-0558: When a Stolen Signing Key Forges Any Token
A single stolen token-signing key let attackers mint valid cloud identities and read email in about 25 organizations. Root cause, blast radius, and what to do about your own keys.
CircleCI Breach: Stolen Session Cookies and Your CI Secrets
One infected engineer laptop, one stolen SSO session, and every customer secret in CircleCI was in play. What failed, the blast radius, and how to make CI secrets cheap to rotate.
The chalk/debug npm Compromise: Anatomy of a Package Hijack
One phished maintainer turned 18 ubiquitous npm packages into a crypto-stealing payload in about two hours. Here is how it worked and the build-pipeline controls that blunt it.