VYPR
Unrated severityNVD Advisory· Published May 25, 2026

Missing Authorization Validation in mlflow/mlflow

CVE-2026-2651

Description

A vulnerability in MLflow versions <=3.10.1.dev0 allows unauthorized access to multipart upload (MPU) endpoints when the --serve-artifacts mode is enabled. The authorization logic does not enforce resource-level permission checks for /mlflow-artifacts/mpu/* endpoints, enabling attackers to overwrite artifacts belonging to other users. This can lead to unauthorized cross-user writes, model supply chain poisoning, and arbitrary code execution when compromised models are loaded. The issue is resolved in version 3.10.0.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

MLflow <=3.10.1.dev0 with --serve-artifacts lacks authorization for multipart upload endpoints, allowing cross-user artifact overwrite and potential RCE.

Vulnerability

The vulnerability exists in MLflow versions up to 3.10.1.dev0 when the --serve-artifacts mode is enabled. The authorization logic fails to enforce resource-level permission checks on /mlflow-artifacts/mpu/* endpoints (create, complete, abort). This allows any authenticated user to perform multipart upload operations on artifacts belonging to other experiments or runs. The issue is resolved in version 3.10.0 [1][2].

Exploitation

An attacker needs network access to an MLflow server with --serve-artifacts enabled and valid authentication credentials (any user account). The attacker can send crafted POST requests to endpoints such as /api/2.0/mlflow-artifacts/mpu/create/{experiment_id}/artifacts/model to initiate a multipart upload, then complete or abort the upload, effectively overwriting artifacts in another user's experiment. No additional permissions are required beyond basic authentication [1].

Impact

Successful exploitation allows an attacker to overwrite arbitrary artifacts, including model files, belonging to other users. This can lead to model supply chain poisoning: when a compromised model is loaded by another user or automated pipeline, it can result in arbitrary code execution. The impact is high, as it compromises the integrity and availability of ML models and can lead to full system compromise in the context of the MLflow server [2].

Mitigation

The fix is included in MLflow version 3.10.0. Users should upgrade to 3.10.0 or later immediately. If upgrading is not possible, disabling --serve-artifacts mode is a workaround, though this may impact functionality. No other mitigations are documented in the available references [1][2].

AI Insight generated on May 25, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

1
d7290811d8f3

Auth support for MPU endpoints (#20919)

https://github.com/mlflow/mlflowTomuHirataFeb 18, 2026via nvd-ref
2 files changed · +44 0
  • mlflow/server/auth/__init__.py+3 0 modified
    @@ -1641,6 +1641,8 @@ def _is_proxy_artifact_path(path: str) -> bool:
         prefixes = [
             f"{_REST_API_PATH_PREFIX}/mlflow-artifacts/artifacts",
             f"{_AJAX_API_PATH_PREFIX}/mlflow-artifacts/artifacts",
    +        f"{_REST_API_PATH_PREFIX}/mlflow-artifacts/mpu/",
    +        f"{_AJAX_API_PATH_PREFIX}/mlflow-artifacts/mpu/",
         ]
         return any(path.startswith(prefix) for prefix in prefixes)
     
    @@ -1655,6 +1657,7 @@ def _get_proxy_artifact_validator(
             "GET": validate_can_read_experiment_artifact_proxy,  # Download
             "PUT": validate_can_update_experiment_artifact_proxy,  # Upload
             "DELETE": validate_can_delete_experiment_artifact_proxy,  # Delete
    +        "POST": validate_can_update_experiment_artifact_proxy,  # Multipart upload
         }.get(method)
     
     
    
  • tests/server/auth/test_auth.py+41 0 modified
    @@ -114,6 +114,27 @@ def test_proxy_artifact_path_detection():
         assert auth_module._is_proxy_artifact_path("/ajax-api/2.0/mlflow-artifacts/artifacts/foo")
     
     
    +def test_proxy_artifact_mpu_path_detection():
    +    # MPU create/complete/abort paths should be recognized as proxy artifact paths
    +    for action in ("create", "complete", "abort"):
    +        assert auth_module._is_proxy_artifact_path(
    +            f"/api/2.0/mlflow-artifacts/mpu/{action}/1/run-id/artifacts/model"
    +        )
    +        assert auth_module._is_proxy_artifact_path(
    +            f"/ajax-api/2.0/mlflow-artifacts/mpu/{action}/1/run-id/artifacts/model"
    +        )
    +
    +    # Non-artifact paths should not match
    +    assert not auth_module._is_proxy_artifact_path("/api/2.0/mlflow/experiments/get")
    +
    +
    +def test_proxy_artifact_mpu_validator_returns_update_for_post():
    +    validator = auth_module._get_proxy_artifact_validator(
    +        "POST", {"artifact_path": "1/run-id/artifacts/model"}
    +    )
    +    assert validator is auth_module.validate_can_update_experiment_artifact_proxy
    +
    +
     def test_proxy_artifact_authorization_required(client, monkeypatch):
         username1, password1 = create_user(client.tracking_uri)
         username2, password2 = create_user(client.tracking_uri)
    @@ -132,6 +153,26 @@ def test_proxy_artifact_authorization_required(client, monkeypatch):
         assert response.status_code == 403
     
     
    +@pytest.mark.parametrize("mpu_action", ["create", "complete", "abort"])
    +def test_mpu_authorization_required(client, monkeypatch, mpu_action):
    +    username1, password1 = create_user(client.tracking_uri)
    +    username2, password2 = create_user(client.tracking_uri)
    +
    +    with User(username1, password1, monkeypatch):
    +        experiment_id = client.create_experiment(f"mpu-authz-test-{mpu_action}")
    +
    +    # user2 has no permission on user1's experiment — expect 403
    +    response = requests.post(
    +        url=(
    +            client.tracking_uri
    +            + f"/api/2.0/mlflow-artifacts/mpu/{mpu_action}/{experiment_id}/artifacts/model"
    +        ),
    +        json={"path": "python_model.pkl", "num_parts": 1},
    +        auth=(username2, password2),
    +    )
    +    assert response.status_code == 403
    +
    +
     def _mlflow_search_experiments_rest(base_uri, headers):
         response = requests.post(
             f"{base_uri}/api/2.0/mlflow/experiments/search",
    

Vulnerability mechanics

Root cause

"Missing authorization enforcement for multipart upload (MPU) endpoints — the path prefix and HTTP method were not recognized as requiring artifact-level permission checks."

Attack vector

An attacker with valid MLflow credentials can send POST requests to `/api/2.0/mlflow-artifacts/mpu/{action}/{experiment_id}/artifacts/{path}` endpoints (for `create`, `complete`, or `abort` actions) targeting an experiment owned by another user. Because the authorization logic did not treat these MPU paths as proxy artifact paths, no resource-level permission check was enforced, allowing the attacker to overwrite artifacts belonging to other users when `--serve-artifacts` mode is enabled [patch_id=2473740]. This can lead to model supply chain poisoning and arbitrary code execution when compromised models are loaded.

Affected code

The authorization logic in `mlflow/server/auth/__init__.py` did not recognize multipart upload (MPU) endpoint paths (`/mlflow-artifacts/mpu/`) as proxy artifact paths. The `_is_proxy_artifact_path()` function only checked for the `/mlflow-artifacts/artifacts` prefix, and the `_get_proxy_artifact_validator()` method had no mapping for the `POST` HTTP method, which MPU create/complete/abort actions use [patch_id=2473740].

What the fix does

The patch adds two changes to `mlflow/server/auth/__init__.py`. First, it extends `_is_proxy_artifact_path()` to recognize paths starting with `/mlflow-artifacts/mpu/` (both REST and AJAX API prefixes), so MPU endpoints are treated as proxy artifact paths. Second, it adds a `"POST"` entry to `_get_proxy_artifact_validator()` that maps POST requests to `validate_can_update_experiment_artifact_proxy`, ensuring that multipart upload operations undergo the same experiment-level authorization check as regular artifact uploads [patch_id=2473740].

Preconditions

  • configMLflow server must be running with --serve-artifacts mode enabled
  • authAttacker must have valid MLflow credentials (any user account)
  • inputTarget experiment must exist and be owned by a different user
  • networkNetwork access to the MLflow server's API endpoints

Generated on May 25, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.