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.
4 steps from start to impact.
Discover exposed MLflow instance
- MLflow instance is network-reachable (internet or internal network)
- Instance is running with
--app-name basic-auth
- 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
http.title:"MLflow" or port 5000 with MLflow response headers. Network IDS can detect scanning patterns.Confirm ASGI/uvicorn serving
/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.- Target is served via uvicorn (ASGI), not gunicorn (WSGI)
- FastAPI routes are mounted and active
- 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
/ajax-api/ and /v1/traces paths. Access logs will show unauthenticated 200 responses on these endpoints.Submit malicious jobs via Job API
/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.- Job API accepts job submission payloads
- Compute backend executes submitted job code
- 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
Inject poisoned trace data
/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.- OpenTelemetry trace ingestion is active
- Downstream systems consume trace data for decisions
- Trace injection alone does not grant code execution
- Impact depends on whether automated pipelines trust trace data without validation
The supporting signals.
| In-the-Wild Exploitation | No confirmed active exploitation. Not on CISA KEV. EPSS at 97th percentile signals high predicted exploitability but no campaigns observed yet. |
|---|---|
| Proof of Concept | No 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 Score | 0.18861 (97th percentile) — places this in the top 3% of all CVEs for predicted exploitation probability within 30 days. |
| KEV Status | Not listed on CISA KEV as of 2026-08-10. |
| CVSS Vector | CVSS: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 Versions | MLflow < 3.11.0 (GHSA scope). Originally reported against ≤ 3.9.0 but the GitHub advisory expanded the affected range. |
| Fixed Version | MLflow 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 Date | 2026-05-15 |
| Reporter | Reported via huntr.com bug bounty program. No individual researcher credited in the GHSA advisory. |
noisgate verdict.
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.
Why this verdict
- Configuration prerequisites narrow the population: The target must run with
--app-name basic-authAND 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;
curlsuffices. 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.
What to do — in priority order.
- Block unauthenticated access to
/ajax-api/and/v1/tracesat 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. - 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.
- 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. - 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.
- 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.
- 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.
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.
#!/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
fiIf you remember one thing.
--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
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.