Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-69148

CVE-2026-69148: MLflow Authorization Bypass Vulnerability

CVE-2026-69148 is an authorization bypass flaw in MLflow that allows authenticated users to access other users' artifact directories without proper permissions. This article covers technical details, affected versions, security impact, and mitigation steps.

Published:

CVE-2026-69148 Overview

CVE-2026-69148 is a missing authorization flaw [CWE-862] in MLflow, an open source platform for managing agents, large language models, and machine learning models. Prior to version 3.15.0, the CreateModelVersion handler accepts a run_id or model_id after _validate_source_run() or _validate_source_model() in mlflow/server/handlers.py verifies only path containment. Authenticated users can create a model version that references another user's artifact directory and read files through GET /model-versions/get-artifact without holding the required READ permission. Version 3.15.0 fixes the issue.

Critical Impact

Authenticated users can read artifacts owned by other tenants by anchoring a new model version to a run or model they do not own.

Affected Products

  • MLflow versions prior to 3.15.0
  • MLflow deployments using the built-in authentication server (mlflow.server.auth)
  • Multi-tenant MLflow tracking and model registry environments

Discovery Timeline

  • 2026-08-17 - CVE-2026-69148 published to NVD
  • 2026-08-18 - Last updated in NVD database

Technical Details for CVE-2026-69148

Vulnerability Analysis

MLflow's model registry stores each model version's source inside the artifact directory of a run or logged model. The CreateModelVersion endpoint requires the caller to hold update rights on the target registered model, but it did not require READ on the source run or model referenced by run_id/model_id. Downstream artifact reads through GET /model-versions/get-artifact are gated on the registered model, not the underlying run. An attacker can register a new version pointing at another tenant's artifact directory and then retrieve its files through their own registered model.

Root Cause

The pre-patch validators _validate_source_run() and _validate_source_model() in mlflow/server/handlers.py only confirmed that source sits within an allowed artifact path. They did not consult the authorization layer to verify that the caller can read the source run or model. This is a classic missing authorization check [CWE-862] where path containment was conflated with access control.

Attack Vector

An authenticated user with permission to create model versions on a registered model they control sends a CreateModelVersion request whose run_id or model_id references a run or model owned by another user. The server accepts the request, creates a version anchored to the victim's artifact directory, and subsequent GET /model-versions/get-artifact calls return the victim's files.

python
     return _get_permission_from_registered_model_or_prompt_name().can_manage


+def validate_can_create_model_version():
+    # A model version anchors its `source` inside the artifact directory of the run/model
+    # named by `run_id`/`model_id`. Downstream artifact reads are gated on the model version's
+    # registered model, so without a read check here a caller could point `source` at another
+    # user's run/model and read those artifacts through their own registered model. Require read
+    # on the source run/model to keep create-time access consistent with artifact-read gating.
+    if not _validate_can_update_registered_model_or_prompt():
+        return False
+    body = request.get_json(force=True, silent=True)
+    body = body if isinstance(body, dict) else {}
+    # Presence of run_id/model_id means the version is anchored to that source, so require
+    # READ on it. Guard on presence (not truthiness): an explicitly-supplied empty id is
+    # denied here rather than being allowed to slip past the guard as if it were absent.
+    if "run_id" in body and not (body["run_id"] and _get_permission_from_run_id().can_read):
+        return False
+    if "model_id" in body and not (body["model_id"] and _get_permission_from_model_id().can_read):
+        return False
+    return True
+
+
 def validate_can_create_experiment() -> bool:
     return _user_can_create_in_workspace()

Source: GitHub Commit 4bb7474. The patch introduces validate_can_create_model_version() in mlflow/server/auth/__init__.py, which requires READ permission on any run_id or model_id supplied in the request body before the version is created.

Detection Methods for CVE-2026-69148

Indicators of Compromise

  • CreateModelVersion requests where the authenticated user's identity does not match the owner of the referenced run_id or model_id.
  • GET /model-versions/get-artifact responses returning files whose underlying storage path belongs to a different user's experiment or logged-model directory.
  • New model versions whose source URI resolves outside the caller's own experiment or model artifact roots.

Detection Strategies

  • Correlate MLflow audit logs across CreateModelVersion and GetModelVersionArtifact calls, flagging chains where the source run or model belongs to a different principal than the registered model owner.
  • Parse the source field of newly created model versions and compare its artifact path against the caller's authorized experiments and logged models.
  • Alert on 2xx responses to /api/2.0/mlflow/model-versions/create when the request body contains a run_id or model_id that the caller lacks READ on in the MLflow permissions store.

Monitoring Recommendations

  • Forward MLflow server access logs and the auth database to a centralized SIEM for cross-user access pattern analysis.
  • Track the version distribution of MLflow servers across the environment and alert on any instance running below 3.15.0.
  • Baseline per-user artifact download volume and rate; investigate deviations that follow model version creation events.

How to Mitigate CVE-2026-69148

Immediate Actions Required

  • Upgrade all MLflow tracking servers to version 3.15.0 or later.
  • Inventory existing model versions and validate that each source URI belongs to a run or logged model owned by, or explicitly shared with, the registering user.
  • Rotate any secrets, tokens, or credentials that may have been stored inside experiment artifacts on multi-tenant MLflow deployments.

Patch Information

The fix is included in MLflow 3.15.0 via Pull Request #24293 and commit 4bb7474. Full advisory details are available in GHSA-gqch-g4w5-7qcw. The patch adds validate_can_create_model_version(), enforcing READ on run_id and model_id at model version creation time.

Workarounds

  • Restrict CreateModelVersion privileges to a small set of trusted service accounts until the upgrade is complete.
  • Place MLflow behind a reverse proxy that inspects /model-versions/create payloads and rejects requests referencing run_id or model_id values outside the caller's namespace.
  • Isolate tenants into separate MLflow instances with dedicated artifact stores where cross-tenant registration is not required.
bash
# Upgrade MLflow to the patched release
pip install --upgrade 'mlflow>=3.15.0'

# Verify the running server version
mlflow --version

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.