CVE-2026-2652 Overview
CVE-2026-2652 is an authentication bypass vulnerability in mlflow/mlflow versions 3.9.0 and earlier. The FastAPI permission middleware only enforces authentication on /gateway/ routes when MLflow runs with --app-name basic-auth under uvicorn (ASGI). Other endpoints, including the Job API (/ajax-api/3.0/jobs/*) and the OpenTelemetry trace ingestion API (/v1/traces), remain unprotected. Unauthenticated remote attackers can submit jobs, read job results, cancel running jobs, and inject arbitrary trace data into experiments. The flaw is fixed in mlflow 3.10.0.
Critical Impact
Remote, unauthenticated attackers can submit and cancel MLflow jobs, retrieve job results, and inject forged telemetry into experiments on servers running with basic-auth enabled.
Affected Products
- mlflow/mlflow versions 3.9.0 and earlier (server started with --app-name basic-auth)
- MLflow deployments served via uvicorn (ASGI)
- LF Projects MLflow tracking server with FastAPI permission middleware
Discovery Timeline
- 2026-05-15 - CVE-2026-2652 published to NVD
- 2026-05-18 - Last updated in NVD database
Technical Details for CVE-2026-2652
Vulnerability Analysis
MLflow historically used Flask for HTTP handling, with authentication enforced through Flask before_request hooks. Version 3.x introduced FastAPI routes served via uvicorn for newer subsystems such as the GenAI gateway, the Jobs API, and OpenTelemetry trace ingestion. The basic-auth application wires a FastAPI permission middleware to bridge the two stacks. That middleware only inspects requests targeting /gateway/ paths and short-circuits everything else as authenticated. Mapped to [CWE-305], this is a failure of authentication for a critical function caused by incomplete route coverage in the middleware.
Root Cause
The _find_fastapi_validator() helper in mlflow/server/auth/__init__.py returns no validator for non-/gateway/ paths. The FastAPI permission middleware treats the absent validator as a pass condition, so requests skip credential checks entirely. The patch adds explicit validators for additional FastAPI route groups and refactors permission lookup into _get_experiment_permission() so callers other than Flask handlers can enforce ACLs.
Attack Vector
The attack vector is network-based and requires no authentication or user interaction. An attacker reaches the MLflow tracking server on its HTTP listener and issues requests directly to the unprotected FastAPI routes. Sending POST requests to /ajax-api/3.0/jobs/* allows job submission, cancellation, and result retrieval. Sending OTLP payloads to /v1/traces injects attacker-controlled spans into experiment telemetry, polluting downstream evaluation and model lineage data.
def _get_permission_from_experiment_id() -> Permission:
experiment_id = _get_request_param("experiment_id")
username = authenticate_request().username
+ return _get_experiment_permission(experiment_id, username)
+
+
+def _get_experiment_permission(experiment_id: str, username: str) -> Permission:
return _get_permission_from_store_or_default(
lambda: store.get_experiment_permission(experiment_id, username).permission,
workspace_level_permission_func=lambda: _workspace_permission_for_experiment(
Source: MLflow security patch commit bb62e77 — the fix extracts permission resolution into a reusable helper so FastAPI validators can enforce experiment ACLs equivalent to the Flask path.
Detection Methods for CVE-2026-2652
Indicators of Compromise
- Requests to /ajax-api/3.0/jobs/* with no Authorization header or session cookie reaching an MLflow server configured for basic-auth.
- POST requests to /v1/traces carrying OTLP payloads from clients not part of the authorized training pipeline.
- Unexpected job submissions, cancellations, or experiment trace records lacking a corresponding authenticated user in MLflow audit logs.
Detection Strategies
- Inspect MLflow access logs for HTTP 200 responses on FastAPI routes outside /gateway/ that are missing credentials.
- Compare experiment trace ingestion patterns against the known list of authorized ML pipelines and flag origin IPs that are not on that allowlist.
- Alert on MLflow job lifecycle events (submit, cancel, get-result) where the requesting principal is empty or null.
Monitoring Recommendations
- Forward MLflow server logs and reverse proxy access logs to a SIEM and build a rule for unauthenticated requests to /ajax-api/3.0/jobs/* and /v1/traces.
- Monitor outbound network connections from MLflow job workers, since attacker-submitted jobs execute arbitrary code under the worker identity.
- Track the MLflow package version across deployments and alert when any host runs mlflow <= 3.9.0 with basic-auth enabled.
How to Mitigate CVE-2026-2652
Immediate Actions Required
- Upgrade MLflow to version 3.10.0 or later on all tracking servers using --app-name basic-auth.
- Restrict network access to MLflow tracking servers to known client subnets until the upgrade is complete.
- Audit job history and experiment traces created on vulnerable versions for unauthorized submissions or forged spans.
Patch Information
The vulnerability is fixed in mlflow 3.10.0 by commit bb62e77 (MLflow GitHub commit). The patch adds authentication validators for the previously unprotected FastAPI routes and exposes _get_experiment_permission() so the FastAPI middleware can enforce experiment-level ACLs. Additional context is available in the Huntr bounty report.
Workarounds
- Place the MLflow tracking server behind an authenticating reverse proxy (for example, nginx with auth_request or an OAuth2 proxy) that requires credentials for every path, not just /gateway/.
- Block external access to /ajax-api/3.0/jobs/ and /v1/traces at the network or proxy layer until MLflow is upgraded.
- Disable the Jobs API and OpenTelemetry trace ingestion endpoints if they are not required by the deployment.
# Reverse proxy snippet to deny unauthenticated access to vulnerable FastAPI routes
location ~ ^/(ajax-api/3\.0/jobs|v1/traces) {
auth_request /_auth;
proxy_pass http://mlflow_upstream;
}
location = /_auth {
internal;
proxy_pass http://auth_service/validate;
proxy_set_header Authorization $http_authorization;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


