← Back to Feed CACHED · 2026-08-10 13:27:32 · CACHE_KEY CVE-2026-2652
CVE-2026-2652 · CWE-305 · Disclosed 2026-05-15

A vulnerability in mlflow/mlflow versions 3.9.0 and earlier

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

Like a bouncer who only checks IDs at the VIP entrance while the kitchen door swings wide open

CVE-2026-2652 is an authentication bypass in MLflow versions prior to 3.11.0 (originally reported against ≤3.9.0). When the server is launched with --app-name basic-auth and served via uvicorn (ASGI), the FastAPI permission middleware only enforces authentication on /gateway/ routes. The Job API (/ajax-api/3.0/jobs/*) and the OpenTelemetry trace ingestion API (/v1/traces) are left completely unprotected. An unauthenticated remote attacker can submit arbitrary jobs, read job results, cancel running jobs, and inject trace data into experiments. The root cause is an architectural mismatch in _find_fastapi_validator() between Flask and FastAPI auth handling — it simply does not validate non-gateway paths.

The vendor scored this 8.6 HIGH, which is directionally correct but slightly generous. The CVSS vector (AV:N/AC:L/PR:N/UI:N) accurately reflects the zero-interaction, unauthenticated remote attack surface. However, the vendor score does not account for the configuration prerequisites: the target must be running with --app-name basic-auth AND served specifically via uvicorn ASGI — not the default gunicorn/WSGI configuration. MLflow instances with no auth at all (a disturbingly common posture) are not *more* vulnerable via this CVE; they're already wide open through other means. This narrows the actually-affected population. That said, the ML supply-chain implications of arbitrary job submission on a model training platform keep this firmly in HIGH territory.

"Auth bypass on MLflow FastAPI routes lets attackers submit jobs unauthenticated — ML supply chain risk keeps this HIGH"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Discover exposed MLflow instance

Attacker scans for MLflow Tracking Servers on port 5000 (default) using Shodan, Censys, or FOFA. Approximately 3,000 MLflow instances are publicly discoverable. The attacker identifies a target running with authentication enabled (login page present).
Conditions required:
  • MLflow instance is network-reachable (internet or internal network)
  • Instance is running with --app-name basic-auth
Where this breaks in practice:
  • Many MLflow instances run with NO auth at all, making this CVE irrelevant — they're already fully exposed
  • Instances behind VPN/private network reduce the Shodan-discoverable population significantly
Detection/coverage: Shodan dork: http.title:"MLflow" or port 5000 with MLflow response headers. Network IDS can detect scanning patterns.
STEP 02

Confirm ASGI/uvicorn serving

Attacker sends requests to FastAPI-specific routes like /ajax-api/3.0/jobs/ or /v1/traces. If the server responds with structured JSON rather than a 404 or redirect, it confirms the uvicorn ASGI backend is active. This also confirms the auth bypass is exploitable — the route responds without requiring credentials.
Conditions required:
  • Target is served via uvicorn (ASGI), not gunicorn (WSGI)
  • FastAPI routes are mounted and active
Where this breaks in practice:
  • Default MLflow deployment uses gunicorn/Flask WSGI, not uvicorn — only newer or explicitly configured deployments use ASGI
  • No public PoC exists yet to automate this fingerprinting
Detection/coverage: WAF rules can block unauthenticated requests to /ajax-api/ and /v1/traces paths. Access logs will show unauthenticated 200 responses on these endpoints.
STEP 03

Submit malicious jobs via Job API

Attacker crafts POST requests to /ajax-api/3.0/jobs/ to submit new jobs. Depending on the MLflow deployment's compute backend, submitted jobs may execute arbitrary training code on the underlying infrastructure. The attacker can also GET existing job results to exfiltrate experiment data, model parameters, and potentially credentials stored in environment variables.
Conditions required:
  • Job API accepts job submission payloads
  • Compute backend executes submitted job code
Where this breaks in practice:
  • Job execution depends on the backend configuration — not all deployments have active compute backends attached
  • Job payloads may be validated or sandboxed depending on deployment
Detection/coverage: Monitor for unexpected job creation events in MLflow audit logs. SIEM alert on job submissions from unauthenticated sessions.
STEP 04

Inject poisoned trace data

Attacker sends crafted payloads to /v1/traces to inject arbitrary OpenTelemetry trace data into experiments. This pollutes experiment tracking, can manipulate model evaluation metrics, and may influence automated model promotion pipelines that rely on trace-derived metrics for deployment decisions.
Conditions required:
  • OpenTelemetry trace ingestion is active
  • Downstream systems consume trace data for decisions
Where this breaks in practice:
  • Trace injection alone does not grant code execution
  • Impact depends on whether automated pipelines trust trace data without validation
Detection/coverage: Anomaly detection on trace ingestion volume and source IPs. Validate trace data provenance in downstream pipelines.
03 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNo confirmed active exploitation. Not on CISA KEV. EPSS at 97th percentile signals high predicted exploitability but no campaigns observed yet.
Proof of ConceptNo public PoC available as of 2026-08-10. Reported via huntr.com bounty. Exploitation is trivial — a single unauthenticated HTTP request to the Job API suffices.
EPSS Score0.18861 (97th percentile) — places this in the top 3% of all CVEs for predicted exploitation probability within 30 days.
KEV StatusNot listed on CISA KEV as of 2026-08-10.
CVSS VectorCVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L — Network-accessible, no privileges, no user interaction. Integrity impact is HIGH (job submission/manipulation), confidentiality and availability are LOW.
Affected VersionsMLflow < 3.11.0 (GHSA scope). Originally reported against ≤ 3.9.0 but the GitHub advisory expanded the affected range.
Fixed VersionMLflow 3.11.0 (commit bb62e77)
Exposure Data~3,000 MLflow instances publicly discoverable via Shodan. MLflow exposure grew 173% in the first half of 2026 per OpenA2A Research. Many run on default port 5000 with no authentication at all.
Disclosure Date2026-05-15
ReporterReported via huntr.com bug bounty program. No individual researcher credited in the GHSA advisory.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to HIGH (7.5/10)

The single most decisive factor keeping this at HIGH despite configuration prerequisites is the role multiplier: MLflow is canonically ML infrastructure, and the ability to submit arbitrary jobs unauthenticated constitutes a supply-chain pivot risk on model training pipelines. The configuration narrowing (basic-auth + uvicorn ASGI required) prevents an upgrade to CRITICAL but cannot pull below the HIGH floor.

HIGH Vulnerability mechanics and affected version range
MEDIUM Real-world exploitability given configuration prerequisites
LOW Fraction of deployments using basic-auth + uvicorn ASGI specifically

Why this verdict

  • Configuration prerequisites narrow the population: The target must run with --app-name basic-auth AND uvicorn ASGI — not the default gunicorn/WSGI setup. This eliminates a significant fraction of deployments. Instances with no auth at all are not additionally vulnerable via this CVE.
  • No auth required for exploitation: Once a qualifying instance is found, the attack is trivially simple — a single unauthenticated HTTP request. No PoC is needed; curl suffices. The CVSS vector correctly reflects PR:N/UI:N.
  • EPSS at 97th percentile signals high predicted exploitation: Despite no current KEV listing or observed campaigns, the statistical model places this in the top 3% for near-term exploitation probability.
  • Role multiplier: MLflow is canonically an ML pipeline infrastructure component (CI/CD + artifact store category). In production deployments, MLflow manages model artifacts, experiment metadata, and training jobs. The ability to submit arbitrary jobs constitutes potential code execution on the training backend — a supply-chain pivot on ML model production. This role represents the *majority* of MLflow installations by definition (it's purpose-built for this), placing the blast radius at supply-chain scale. The HIGH floor applies.
  • ~3,000 publicly exposed instances: Shodan data confirms a non-trivial internet-facing population, and MLflow exposure grew 173% in H1 2026. The attack surface is growing, not shrinking.

Why not higher?

CRITICAL would require either active exploitation (KEV), a broader affected configuration (all MLflow deployments rather than basic-auth + ASGI only), or direct RCE confirmed in the default job execution backend. The configuration prerequisites meaningfully narrow the reachable population below what a CRITICAL rating demands. No public PoC or confirmed campaigns exist yet.

Why not lower?

The unauthenticated, zero-interaction attack surface (AV:N/AC:L/PR:N/UI:N) combined with MLflow's canonical role as ML infrastructure means the floor is HIGH. Arbitrary job submission on a model training platform is supply-chain risk by definition — model poisoning, credential exfiltration from training environments, and lateral movement into compute backends are all plausible outcomes. EPSS at 97th percentile independently supports HIGH.

05 · Compensating Control

What to do — in priority order.

  1. Block unauthenticated access to /ajax-api/ and /v1/traces at the reverse proxy or WAF — Add deny rules in your nginx/Traefik/Cloudflare WAF config to require authentication on these paths. This is the fastest mitigation — deploy within the noisgate mitigation SLA of 30 days for HIGH, but ideally within days given the trivial exploitability.
  2. Restrict MLflow network exposure to internal-only via firewall rules — MLflow Tracking Servers should not be internet-facing. Place them behind VPN or zero-trust network access. If already internal-only, validate that firewall rules prevent lateral access from untrusted segments. Deploy within 30 days per noisgate mitigation SLA.
  3. Upgrade to MLflow 3.11.0 — The definitive fix. The patched _find_fastapi_validator() correctly enforces auth on all FastAPI routes. Schedule within the 180-day noisgate remediation SLA for HIGH.
  4. Switch to gunicorn/WSGI serving if ASGI is not required — If your deployment does not specifically need uvicorn ASGI features, switching to gunicorn/Flask WSGI eliminates this attack vector entirely as the vulnerable FastAPI middleware is not loaded.
  5. Audit MLflow job submission logs for unauthorized entries — Review /ajax-api/3.0/jobs/ access logs for unauthenticated requests since deployment. Look for job submissions from unexpected source IPs. This is forensic, not preventive — do it now.
What doesn't work
  • Network segmentation alone does not help if the attacker has internal network access (post-initial-access). The auth bypass works from any network position that can reach the MLflow port.
  • Enabling basic-auth is actually what *creates* the vulnerable configuration — MLflow without basic-auth has no auth at all, which is a different (and arguably worse) problem but not this CVE.
  • Rate limiting does not mitigate this — a single request is sufficient to submit a malicious job.
06 · Verification

Crowdsourced verification payload.

Run this script on any host that can reach the target MLflow instance. Usage: bash check_cve_2026_2652.sh <mlflow_url> (e.g., bash check_cve_2026_2652.sh https://mlflow.internal:5000). No special privileges required — it only sends unauthenticated HTTP requests.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-2652 Checker — MLflow FastAPI Auth Bypass
# Tests whether /ajax-api/3.0/jobs/ and /v1/traces are accessible without auth
# Exit codes: 0 = VULNERABLE, 1 = PATCHED, 2 = UNKNOWN

set -euo pipefail

if [ $# -lt 1 ]; then
  echo "Usage: $0 <mlflow_base_url>"
  echo "Example: $0 https://mlflow.internal:5000"
  exit 2
fi

BASE_URL="${1%/}"
VULN=0

echo "[*] Testing CVE-2026-2652 against $BASE_URL"
echo

# Test 1: Job API endpoint (should require auth)
echo "[*] Test 1: Checking /ajax-api/3.0/jobs/ (unauthenticated)..."
HTTP_CODE_JOBS=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 10 --max-time 15 "$BASE_URL/ajax-api/3.0/jobs/" 2>/dev/null || echo "000")
echo "    HTTP response: $HTTP_CODE_JOBS"

if [[ "$HTTP_CODE_JOBS" =~ ^(200|201|204|405)$ ]]; then
  echo "    [!] Job API accessible WITHOUT authentication"
  VULN=1
elif [[ "$HTTP_CODE_JOBS" =~ ^(401|403)$ ]]; then
  echo "    [+] Job API correctly requires authentication"
elif [[ "$HTTP_CODE_JOBS" == "404" ]]; then
  echo "    [?] Job API not found — may not be running ASGI/FastAPI"
elif [[ "$HTTP_CODE_JOBS" == "000" ]]; then
  echo "    [?] Connection failed"
  echo "UNKNOWN — could not connect to $BASE_URL"
  exit 2
fi

# Test 2: Traces endpoint (should require auth)
echo "[*] Test 2: Checking /v1/traces (unauthenticated)..."
HTTP_CODE_TRACES=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 10 --max-time 15 "$BASE_URL/v1/traces" 2>/dev/null || echo "000")
echo "    HTTP response: $HTTP_CODE_TRACES"

if [[ "$HTTP_CODE_TRACES" =~ ^(200|201|204|405)$ ]]; then
  echo "    [!] Traces API accessible WITHOUT authentication"
  VULN=1
elif [[ "$HTTP_CODE_TRACES" =~ ^(401|403)$ ]]; then
  echo "    [+] Traces API correctly requires authentication"
elif [[ "$HTTP_CODE_TRACES" == "404" ]]; then
  echo "    [?] Traces API not found — may not be running ASGI/FastAPI"
fi

# Test 3: Confirm auth IS enforced on gateway (control test)
echo "[*] Test 3: Control — checking /gateway/ (should require auth)..."
HTTP_CODE_GW=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 10 --max-time 15 "$BASE_URL/gateway/" 2>/dev/null || echo "000")
echo "    HTTP response: $HTTP_CODE_GW"

if [[ "$HTTP_CODE_GW" =~ ^(401|403)$ ]]; then
  echo "    [+] Gateway auth enforced (confirms basic-auth is enabled)"
fi

echo
if [ "$VULN" -eq 1 ]; then
  echo "VULNERABLE — CVE-2026-2652: FastAPI routes bypass authentication"
  exit 0
else
  echo "PATCHED — FastAPI routes appear to enforce authentication correctly"
  exit 1
fi
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: Identify all MLflow instances in your environment — check asset inventory, scan for port 5000, and query Shodan/Censys for any internet-facing deployments. For any instance running with --app-name basic-auth on uvicorn ASGI, immediately add WAF or reverse-proxy rules blocking unauthenticated access to /ajax-api/ and /v1/traces paths. This compensating control should be in place within the noisgate mitigation SLA of 30 days for HIGH-severity findings, though given the trivial exploitability (single curl command) and 97th-percentile EPSS score, faster is better — aim for this week. Review job submission logs for any unauthorized entries since your deployment went live. Schedule the upgrade to MLflow 3.11.0 within the noisgate remediation SLA of 180 days. If you have internet-facing MLflow instances, treat this as an emergency: pull them behind VPN today and patch within days, not weeks.

Sources

  1. GitHub Advisory GHSA-75cm-x2w3-8mgf
  2. NVD — CVE-2026-2652
  3. huntr.com Bounty Report
  4. TheHackerWire — MLflow Unauthenticated API Access Bypass
  5. Vulnerability-Lookup — CVE-2026-2652
  6. OpenA2A Research — Internet-Wide AI Exposure Sweep April 2026
  7. Echelon Shadow AI Radar — Live Exposed AI Infrastructure
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.