MLflow Vulnerability Report
September 8, 2026

Arbitrary Code Execution via Attacker-Controlled loader_module
CVE Number
CVE-2026-79721
Summary
A malicious MLflow PyFunc model artifact can cause arbitrary code execution when loaded using mlflow.pyfunc.load_model(). The model's MLmodel configuration controls the python_function.loader_module and code settings. During model loading, MLflow adds the configured code directory to sys.path and imports the specified loader module. An attacker who controls the model artifact can therefore cause Python code contained in the artifact to execute with the privileges of the process loading the model.
Products Impacted
This vulnerability is present starting 0.0.1.
CVSS Score: 8.6
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
CWE Categorization
CWE-829: Inclusion of Functionality from Untrusted Control Sphere
Details
Mlflow.pyfunc.load_model resolves the supplied model URI to a local model directory, downloading the referenced artifacts when necessary. It then reads the model's MLmodel file and extracts the python_function flavor configuration.
If the flavor specifies a code path, MLflow adds that path to sys.path before importing the module specified by loader_module.
https://github.com/mlflow/mlflow/blob/8a774946bc19b59cecf3c54a733ebab52aa766f5/mlflow/utils/model_utils.py#L314-L315
def _add_code_to_system_path(code_path):
sys.path = [code_path] + sys.pathBoth the code and loader_module values originate from the model's MLmodel configuration. By placing the configured code directory at the beginning of sys.path, MLflow allows the subsequent module import to resolve against files contained within the model artifact.
Python executes module-level statements when a module is imported. Consequently, attacker-controlled code executes before MLflow invokes the module's _load_pyfunc() function.
The same execution primitive can also be delivered through remotely hosted MLflow artifacts. When a runs:/ or models:/ URI is supplied, mlflow.pyfunc.load_model() resolves and downloads the referenced model artifacts before processing the MLmodel configuration.
An attacker who can publish or modify a model artifact that is later loaded by another user can therefore deliver both the malicious MLmodel configuration and the corresponding Python module remotely.
# evil_model/MLmodel
artifact_path: model
flavors:
python_function:
loader_module: payload
code: "."
python_version: "3.9.0"
env:
conda: conda.yaml
virtualenv: python_env.yaml
mlflow_version: 3.1.4
model_uuid: deadbeef-dead-beef-dead-beefdeadbeef
run_id: deadbeef-dead-beef-dead-beefdeadbeef# evil_model/payload.py
print("PWNED!")
def _load_pyfunc(data_path, model_config=None): ...Loading the crafted model causes payload.py to be imported. The module-level print() executes during import, causing `PWNED!` to be printed before _load_pyfunc() is invoked.
# poc.py
import mlflow.pyfunc
mlflow.pyfunc.load_model('./evil_model')
Project URL:
https://github.com/mlflow/mlflow
RESEARCHER: Esteban Tonglet, Security Researcher, HiddenLayer
Related SAI Security Advisory
September 11, 2026
_READ_ONLY_COMMANDS_POSIX expansion adds 31 commands with no path checking, granting unconditional access to the full host filesystem
Mistral Vibe automatically approves a large set of commands that are not subject to the expected workspace path restrictions, allowing files anywhere on the host to be accessed without user approval.
September 11, 2026
Environment variable prefixes stripped from permission check enable RCE via env injection
Mistral Vibe does not consider environment variable assignments when checking whether a command can run without approval, allowing environment controlled behavior in allowlisted programs such as Git to be abused for arbitrary code execution.