MLflow CISA KEV: Is Your AI Stack In Pentest Scope?

CT
CyberOrbit Team
24 min read
Share

The question "do we run MLflow?" should take four minutes to answer. Often it takes four hours and three teams. That gap, not the CVE, is the actual security problem.

Here is how it goes. Someone drops the CISA advisory into the security channel and the security lead asks whether the company runs MLflow. The platform team says they do not manage it. The data team thinks there is an instance but it belongs to the ML engineers. Three hours later an ML engineer confirms there is a tracking server, stood up eighteen months ago by a data scientist who has since moved teams, running in the data science account rather than production, with an instance role attached because training jobs need to read from the data lake and write to the artifact bucket. Someone checks the load balancer. It has been reachable from the public internet since March.

Nobody was negligent in that story. Every decision was reasonable when it was made. A research tool grew into production infrastructure without anyone declaring the moment it changed category.

That is the pattern worth attention. Organisations test the infrastructure they know about. Vulnerability management works off the asset register, pentest scope is derived from the asset list, patch SLAs apply to tracked systems. All of that machinery functions correctly, and all of it sits downstream of an inventory the MLflow server was never added to. The tracking server is the infrastructure nobody knew they had, holding credentials nobody remembered attaching, on a network path nobody reviewed.

🎯Key Takeaway
Patching CVE-2026-64849 closes this specific door. The scope statement is what decides whether anyone ever checks that the door exists, which is why the durable fix is naming the AI and ML asset class in your next statement of work rather than remediating one server this week.

What CISA Added on 19 August

On 19 August 2026, CISA added CVE-2026-64849 to the Known Exploited Vulnerabilities catalog. It is a server-side request forgery flaw (CWE-918) in the MLflow tracking server, carrying a CVSS 3.1 base score of 9.3.

9.3
CVSS 3.1 base score (SSRF with Scope:Changed, credential disclosure not RCE)
Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N. The Scope:Changed metric is doing real work here: hold every other metric constant and flip Scope to Unchanged and the same flaw scores 8.2. The extra 1.1 points are the scoring system recognising that the vulnerability lets an attacker read cloud credential metadata that unlocks resources well beyond the tracking server, rather than executing commands on the host itself.

The affected range is broad: all versions before 3.15.0. That phrasing matters more than usual, because the fix was not backported to any earlier release line. The advisory lists no patched version on the 3.13.x branch or below, so there is nothing you can apply without moving versions. Remediating CVE-2026-64849 means upgrading to 3.15.0 or later, which is a version migration with dependency and compatibility implications, not a routine patch you slot into next Tuesday's window. If your remediation process assumes "apply patch, close ticket", this one will not fit the shape of that process.

The vulnerability was reported by the researcher freeman-bb and independently surfaced through MLflow issue #24179. The project's security advisory GHSA-7gwp-5pfp-969j documents the technical detail.

The KEV listing carries a specific meaning that gets diluted in coverage. CISA does not add vulnerabilities because they score highly or look dangerous. Inclusion requires reliable evidence of active exploitation in the wild. A KEV entry is not a prediction; it is a report that this is already being used against real targets. That changes how you sequence the work, because the window between disclosure and opportunistic mass exploitation has compressed to the point where the first forty-eight hours decide most outcomes for mid-market organisations. To check the published record for this or any other CVE in your stack, use our CVE lookup tool.

31 Jul 2026
MLflow 3.15.0 ships with the connection-time SSRF fix (PR #24258)
2 Aug 2026
GHSA-7gwp-5pfp-969j published to the GitHub Advisory Database
17 Aug 2026
CVE-2026-64849 assigned to the MLflow tracking server SSRF flaw
Within hours of assignment
watchTowr reports honeypot telemetry showing attackers probing cloud-hosted MLflow instances
18 Aug 2026
Exploitation in the wild reported publicly
19 Aug 2026
CISA adds CVE-2026-64849 to the KEV catalog
2 Sep 2026
BOD 26-04 remediation deadline for US federal civilian agencies

The shape of that timeline is the part worth sitting with. The fix was public on 31 July and the advisory two days later. The first publicly reported exploitation came on 17 August, when the CVE identifier was assigned and the flaw became machine-readable to every scanner, feed, and attacker tool that keys off CVE IDs. Whatever was happening quietly before that, the patch had been available for more than a fortnight by the time attackers were visibly looking. That head start did not help the organisations in this post, because you cannot apply a patch to software you do not know you are running.

Knowing a vulnerability is exploited tells you to hurry. Knowing how it works tells you what to check for, and here the mechanism is more instructive than the score.

How the Attack Actually Works

Four moving parts, and the interaction between them is what turns a webhook feature into a credential disclosure path.

The first is the default authentication posture. Running mlflow server with no additional configuration starts a tracking server with no authentication at all. Anyone who can reach the port can read experiments, browse the model registry, and call the API. This is not a hidden trap: MLflow's own network security documentation says plainly that the tracking server should not be exposed to untrusted networks and should sit behind a proxy handling authentication. What happens in practice is that a server deployed inside a VPC boundary in year one acquires an internet-facing load balancer in year two, and nobody revisits the assumption the original deployment was built on.

The second is the model registry webhooks API, also unauthenticated by default. It includes a test endpoint, POST /api/2.0/mlflow/webhooks/{id}/test, which fires the configured webhook synchronously and returns the upstream response body to the caller. That last detail is what makes this severe. Most SSRF is blind: you can make the server send a request but cannot see what came back, so exploitation depends on timing side channels or out-of-band callbacks. Here the response body is handed straight back. It is full-read SSRF, which is the difference between probing your internal network and reading it.

The third part is what makes this an interesting failure rather than a simple oversight. A guard did exist. MLflow PR #20747, shipped in 3.10.0, added _validate_webhook_url, which resolved the hostname in a webhook URL and rejected anything resolving to a non-public IP address. The intent was exactly right: stop webhooks reaching internal services and cloud metadata endpoints.

The fourth part is that the guard had two bypasses, both classic, neither obvious until you have seen them before.

Validation checked the URL you supplied, but the client that later fetched it did not disable redirects. An attacker registers a webhook pointing at a public server they control, passes validation cleanly, and that server responds with a 302 to the metadata endpoint. The client follows it. The validated URL and the fetched URL were never the same thing.
⚠️Validate the connection, not the string
The generalizable lesson has nothing to do with MLflow. The original guard checked the hostname string at validation time, not the actual connection at request time, and that gap is a time-of-check to time-of-use flaw. Any allowlist that inspects a URL before a separate component fetches it has the same weakness. The fix enforces validation at the socket layer, against the peer address the connection actually reaches, on every hop. If you have written URL validation anywhere in your own stack, that is the pattern to copy.

The payoff is cloud credentials. On AWS, a request to the instance metadata service at 169.254.169.254 returns temporary credentials for the IAM role attached to the instance, with equivalents on GCP and Azure. Public reporting on this class of flaw describes attackers using harvested credentials for resource enumeration, deploying cryptominers on available compute, and creating new IAM users so access survives the original vulnerability being closed.

Be precise about what this is. CVE-2026-64849 is credential disclosure via SSRF, not remote code execution. An attacker does not get a shell on the MLflow host. What they get is whatever the stolen identity can do, which is frequently worse.

The Blast Radius Is Bigger Than the Box

The instinct when assessing an exposed internal tool is to ask what is on it. For a compromised tracking server, that is the wrong question. Ask what identity is attached to it, because a stolen instance role gives an attacker whatever that role reaches, from anywhere.

ML infrastructure roles are habitually over-permissioned, for structural rather than careless reasons. Training jobs need broad read access across data stores because feature engineering pulls from wherever the data lives. Artifact logging needs broad write access to model buckets. Nobody knows in advance which datasets the next experiment will touch, so the role is scoped to the class of resource rather than the specific resource. A role written to make experimentation frictionless is, from an attacker's perspective, a general-purpose key to the data platform.

Then the second-order exposures. The artifact store holds trained models, which are intellectual property and sometimes reconstructible training data. The tracking database holds dataset paths that map the internal data estate, and it holds run parameters, which is where credentials get pasted. Logging a connection string or API token as a run parameter is a common shortcut, because it is the fastest way to make an experiment reproducible.

None of this is speculative escalation. The progression from an exposed service to broad lateral movement through a stolen identity is well documented, and we traced exactly that pattern in our analysis of the ShinyHunters Oracle PeopleSoft campaign. The initial foothold is rarely the interesting part of the incident.

See what your external surface exposes, mapped to the controls it touches.

Run a free External Security Check →

The Real Problem Is That Nobody Owns the ML Stack

If you fix MLflow this week and change nothing else, you will read a near-identical advisory about a different tool within a year. The vulnerability is the symptom. The condition is an entire tier of infrastructure with no owner.

MLflow frequently arrives as a transitive dependency rather than a procurement decision. It comes bundled inside a platform, gets pulled in by an internal template, or shows up because a data scientist ran the quickstart on a shared instance and it worked. There was no architecture review because nothing was being architected. Organisations sometimes discover an ML service the same way they discover any unattended workload, which is an unexpected line on the cloud bill.

ℹ️Three teams, zero owners
The data team deployed it, but thinks of itself as a user of infrastructure rather than an operator of it. The platform team did not provision it, so it is not in their Terraform state or their inventory. The security team never inventoried it, because their inventory starts from the asset register and the asset register starts from what platform provisions. The consequences follow mechanically. Not on the asset register means not in vulnerability management, which means a KEV entry generates a ticket for nobody: there is no queue the item can land in. Not in the statement of work means no external party has ever looked, so nothing independent catches what the internal process missed.

MLflow is a useful example precisely because it is unremarkable. The same applies to Kubeflow pipelines, Ray dashboards, Weights and Biases API keys sitting in notebook environments, Jupyter servers with weak or absent authentication, vector databases holding embedded proprietary content, and model serving endpoints accepting requests from wherever the ingress permits. This is a whole class of infrastructure running with cloud credentials attached that security teams have never formally claimed. The highest-value action available here is not patching one server. It is naming an owner for the category.

Ownership decides whether something gets tested. Which brings us to the document that decides what gets tested.

Why Your Last Pentest Didn't Cover This

Open your most recent penetration test statement of work. Search it for "MLflow". Search it for "machine learning". Search it for "notebook". Search it for the hostname of your ML environment. If all four searches return nothing, you have found the gap without running a single test.

That is not a failure by your testing provider. It is a predictable output of how scope gets written. A scope statement is derived from an asset list, the asset list comes from the CMDB or cloud inventory the security team maintains, and the ML environment is in neither. The provider tests what they are given, thoroughly, and reports accurately. The gap was created before anyone signed anything. We made the same argument about perimeter appliances in our analysis of the Fortinet auth bypasses: patching answers this advisory, scope answers the next one.

Three failure modes recur. Scope derived from a CMDB that predates the ML build, so the scope faithfully describes a stale picture. ML living in a separate cloud account for cost attribution and blast radius reasons while the engagement was scoped to production, so the isolation meant to reduce risk removed the environment from testing. And fingerprinting: an unauthenticated tracking server on a non-standard port behind a load balancer presents to a scanner as unremarkable HTTP, and without someone recognising the response as an ML platform it reads as another low-interest internal web app.

Be honest about what a test of this kind can and cannot establish, because vague claims here are how organisations end up with false assurance.

Pros
  • Which of your declared hosts answer on which ports
  • Whether a responding service fingerprints as an ML platform rather than a generic web application
  • Whether that service responds to API requests without authentication
  • A dated, evidenced record that a given asset was reachable from the internet on a given day
Cons
  • Which IAM role is attached and what it can reach (needs a cloud configuration review, not a network test)
  • Whether an internal-only instance is exploitable (needs internal access or an assumed-breach engagement in scope)
  • What the artifact store actually contains (needs granted authentication)
  • Whether MLflow is running in an account you did not declare (testing covers declared scope, not undiscovered assets)

That dated reachability artifact often forces the ownership conversation, because it converts an architectural argument into a documented fact. But the boundary is the point: testing covers declared scope, and it does not discover assets nobody has mentioned. That is exactly why the scope statement, not the test, is the control that matters here.

What Belongs in an AI/ML Scope Statement

The fix is unglamorous. Name the asset classes explicitly in the statement of work, so inclusion does not depend on whether someone remembered to add a hostname to a spreadsheet.

Experiment tracking and model registry (MLflow, Weights and Biases, Neptune, Comet)
Orchestration and pipelines (Kubeflow, Airflow, Ray, Prefect, Dagster)
Notebook and interactive compute (JupyterHub, SageMaker Studio, Databricks workspaces)
Model serving and inference endpoints, including internal-only ones
Feature stores and vector databases (Pinecone, Weaviate, Chroma, pgvector)
Artifact and model storage: the S3, GCS, and Azure Blob containers these systems read from and write to
IAM roles and service accounts attached to all of the above, listed explicitly as an in-scope review item

For each class, ask two questions. Is it reachable, and from where? What identity is attached to it? Nearly every serious finding in this area answers one of those two. The first decides whether an attacker can start, the second decides how far they get.

One caveat on that list, and it matters more than it looks. Several of those names are managed third-party services rather than infrastructure you operate. You cannot put a vendor's hosted platform into your own statement of work and have someone test it, because you do not own the target and you cannot grant authorisation you do not hold. For those, the in-scope item is your side of the boundary: the API keys, the service accounts, the network egress rules, and the data you have pushed into them. Testing the vendor's platform itself requires their written authorisation, and any provider willing to skip that step is telling you something about how they will treat your environment.

One clarification, because these get conflated in vendor conversations. This is infrastructure testing, distinct from testing the behaviour of an LLM application itself, which covers prompt injection, output handling, and agent tool abuse; we cover that separately in our guide to LLM and AI application security testing. Both matter, they are different scopes and often different testers, and an engagement covering one does not cover the other.

What To Do This Week

Six steps, in order, most of which need no budget conversation.

1
Establish whether you run it. Search container registries and image manifests for MLflow images, grep requirements.txt and pyproject.toml across your repositories, check your cloud provider's running services inventory, and ask the data team directly, because the fastest path to an answer is usually a person rather than a query.
2
Establish external reachability. Enumerate subdomains on your domains, including ones the data team created without going through the usual DNS request process, and check whether anything resolving to your ML environment answers from outside your VPC. Our subdomain finder runs the enumeration against domains you own.
3
Upgrade to MLflow 3.15.0 or later. No backport exists, so this is a version move rather than a patch and needs planning time. In the interim, put the tracking server behind a reverse proxy that enforces authentication, restrict inbound access to known networks, and restrict egress so the host cannot reach cloud metadata endpoints. The egress control is the one people skip, and it is the one that neutralises this specific attack regardless of what else is misconfigured.
4
Check for prior compromise. Start with the inbound evidence, because it is the evidence you actually have: tracking server access logs showing calls to /api/2.0/mlflow/webhooks/, particularly the /test endpoint, and any webhook rows in the tracking database pointing at URLs nobody on your team registered. Do not expect to find the outbound request to 169.254.169.254 in your network telemetry: link-local metadata traffic never leaves the instance, so it does not appear in VPC Flow Logs. The reliable signal that credentials were taken is on the identity side. Review CloudTrail for the instance role's session being used from an IP address outside your VPC, and for the follow-on pattern of resource enumeration, new IAM users or access keys, and compute launched in regions you do not operate in. If you run GuardDuty, UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration is the finding that names this directly. KEV means exploited, so this step is not theoretical.
5
Scope down the attached identity. Whatever the role grants today, it almost certainly grants more than the workload needs. Reducing it does not prevent the next vulnerability, but it fixes the multiplier that turns an exposed service into a data platform incident.
6
Add the AI/ML asset class to your next penetration test scope statement. That is the step that changes the outcome next time rather than this time.
⚠️Enforce IMDSv2: the control that breaks this whole attack class
IMDSv2 makes the instance metadata endpoint reject any request that does not carry a session token obtained through a PUT carrying a specific TTL header. A webhook delivery primitive that issues a fixed method to an attacker-supplied URL cannot construct that request, so the SSRF-to-credentials chain breaks even on an unpatched MLflow instance. Setting the metadata hop limit to 1 closes the containerised variant of the same trick. This applies across your whole fleet rather than one service, which is what makes it the highest-leverage item here. It is not free, though: enforcing IMDSv2 rather than merely enabling it will break workloads still using older SDKs or hardcoded IMDSv1 calls, so roll it out in optional mode, watch the MetadataNoToken CloudWatch metric until it sits at zero, then enforce.
The correction that matters here is a line in your next statement of work, not a new tool. Take the checklist above to whoever runs your testing. If that is CyberOrbit: you set the targets, including the environment nobody put on the asset register, we scope and run the assessment, and a certified security professional reviews and signs the report.
Scope an assessment that includes your ML environment

The Compliance Angle

Be accurate about what the KEV catalog obliges you to do, because overstating it is a fast way to lose the room. The CISA KEV catalog binds US federal civilian executive branch agencies under Binding Operational Directive 26-04, with defined remediation deadlines. It does not create a legal obligation for a private mid-market SaaS or fintech company, though if you sell to the federal government it is worth checking whether your contracts flow the requirement down to you. A security leader who knows this and sees a vendor imply otherwise will discount everything else that vendor says.

What KEV is, for the rest of us, is the highest-quality free signal of confirmed in-the-wild exploitation available anywhere. It is evidence-gated, public, and increasingly referenced outside its formal remit: cyber insurers ask about KEV remediation timelines at renewal, and enterprise security questionnaires have started asking whether KEV entries are tracked. Adopting it as a prioritisation input is defensible on its merits, not because anyone requires it.

The obligation that does apply to many organisations here is PCI DSS Requirement 11.4, which covers internal testing at 11.4.2 and external testing at 11.4.3. Both require penetration testing at least once every twelve months and after any significant infrastructure or application upgrade or change, performed by a qualified tester with organisational independence from the systems under test. Standing up a machine learning platform with cloud credentials attached, network reachability, and access to data stores is a significant change by any reasonable reading. But the twelve-month clock and the significant-change trigger both operate on assets someone has declared. An environment that was never scoped was never tested, so the clock never started and the trigger never fired. The compliance gap and the security gap share a root cause.

That is also the clearest argument for treating exposure management as continuous rather than annual. An asset that appears between two point-in-time assessments is invisible to both, which is the framing behind continuous threat exposure management. Acting on it needs no new category of tool. It needs a scope statement that names the class of asset rather than the instance, and a re-inventory cadence shorter than the rate at which your data team creates infrastructure.

Frequently Asked Questions

What is CVE-2026-64849 and which MLflow versions are affected?
CVE-2026-64849 is a server-side request forgery vulnerability (CWE-918) in the MLflow tracking server, with a CVSS 3.1 base score of 9.3. It affects all versions before 3.15.0, which was released on 31 July 2026. The fix was not backported to earlier release lines, so remediation requires upgrading to 3.15.0 or later rather than patching your current version.
Why did CISA add MLflow to the KEV catalog?
CISA added it on 19 August 2026. Inclusion requires reliable evidence of active exploitation in the wild, so the listing confirms attackers are already using this against real targets rather than indicating exploitation is merely likely.
How does the MLflow SSRF vulnerability steal cloud credentials?
The model registry webhook test endpoint makes a server-side HTTP request and returns the response body to the caller. A URL validation guard existed but could be bypassed via HTTP redirects or DNS rebinding, letting an attacker reach the cloud instance metadata service and read temporary IAM credentials for the role attached to the host. This is credential disclosure, not remote code execution.
Does a penetration test cover MLflow and AI/ML infrastructure?
Only if the scope statement says so. Most scopes derive from an asset register that does not include ML infrastructure, which is commonly deployed by data teams outside the platform provisioning process and sometimes in a separate cloud account. Testing covers declared scope; it does not discover undeclared assets.
What should an AI/ML infrastructure penetration test scope include?
Name the classes explicitly: experiment tracking and model registries, orchestration tools, notebook and interactive compute, model serving endpoints, feature stores and vector databases, artifact and model storage, and the IAM roles attached to all of them. For each, establish whether it is reachable and from where, and what identity is attached.
Is MLflow exposed to the internet without authentication by default?
Running mlflow server with default configuration starts a tracking server with no authentication, and MLflow's documentation advises against exposing it to untrusted networks. Exposure usually results from a load balancer or network change made after deployment rather than from the default itself.
How do I check whether my MLflow server was already exploited?
Check tracking server access logs for calls to /api/2.0/mlflow/webhooks/, especially the /test endpoint, and check the tracking database for webhook URLs nobody registered. The outbound request to 169.254.169.254 will not show up in VPC Flow Logs, because link-local metadata traffic never leaves the instance. The dependable signal is on the identity side: CloudTrail showing the instance role's session used from an IP outside your VPC, followed by resource enumeration, new IAM users or access keys, and compute in unused regions.
Does the CISA KEV catalog apply to private companies?
No. KEV creates binding remediation obligations only for US federal civilian executive branch agencies under BOD 26-04, which for CVE-2026-64849 set a due date of 2 September 2026. Private companies have no direct legal obligation to follow it, though federal contractors should check whether their contracts flow the requirement down. It remains the best free source of confirmed exploited-in-the-wild data, and cyber insurers and enterprise questionnaires increasingly reference it.
You configure the targets, including the ML environment nobody put on the asset register. CyberOrbit scopes and runs the assessment, and a certified security professional reviews and signs the audit-ready report your auditor accepts. Where an item needs a cloud configuration review or internal access instead, we will tell you at scoping rather than after.
Get an independent pentest with your AI stack in scope

The security writing, weekly

New posts as they land: findings from real assessments, what the regulatory changes actually mean, and the occasional teardown.

Privacy