High

MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False safety control bypassed by mlflow.statsmodels flavor — RCE via crafted model artifact

  • Disclosed: 01.09.2026
  • Updated: 11.10.2026 15:17

Summary

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:

# mlflow/pyfunc/__init__.py L1170-1172
model_impl = importlib.import_module(conf[MAIN])._load_pyfunc(data_path)

The guarded pattern (from mlflow/sklearn/__init__.py L526-533, the reference implementation) is:

if (
    not MLFLOW_ALLOW_PICKLE_DESERIALIZATION.get()
    and not is_in_databricks_runtime()
    and not is_in_databricks_model_serving_environment()
):
    raise MlflowException("Deserializing model using pickle is disallowed...")

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

python
# L307-320 — no guard anywhere in this file
def _load_model(path):
    import statsmodels.iolib.api as smio
    return smio.load_pickle(path)   # calls pickle.load() directly

def _load_pyfunc(path):
    return _StatsmodelsModelWrapper(_load_model(path))

statsmodels.iolib.api.load_pickle is a thin wrapper around pickle.load. Its own docstring warns: "Never unpickle data received from an untrusted or unauthenticated source."


Trigger

An attacker crafts an MLmodel YAML that specifies mlflow.statsmodels as the loader module:

flavors:
  python_function:
    loader_module: mlflow.statsmodels
    data: model.pkl
  statsmodels:
    data: model.pkl
    statsmodels_version: 0.14.0

With a malicious model.pkl placed alongside it in the artifact store, any call to:

os.environ["MLFLOW_ALLOW_PICKLE_DESERIALIZATION"] = "False"
mlflow.pyfunc.load_model("models:/MaliciousModel/1")

...deserializes the pickle file with no guard check, executing arbitrary code 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:

python
from mlflow.environment_variables import MLFLOW_ALLOW_PICKLE_DESERIALIZATION
from mlflow.utils.databricks_utils import (
    is_in_databricks_model_serving_environment,
    is_in_databricks_runtime,
)

def _load_model(path):
    if (
        not MLFLOW_ALLOW_PICKLE_DESERIALIZATION.get()
        and not is_in_databricks_runtime()
        and not is_in_databricks_model_serving_environment()
    ):
        raise MlflowException(
            "Deserializing model using pickle is disallowed, but this statsmodels "
            "model requires pickle deserialization. Set environment variable "
            "'MLFLOW_ALLOW_PICKLE_DESERIALIZATION' to 'true' to allow this."
        )
    import statsmodels.iolib.api as smio
    return smio.load_pickle(path)

Affected software

Click a technology to see all vulnerabilities affecting it.

PlatformPackageVulnerable versionsFixed in
Python (PyPI) mlflow >= 2.1.0, < 3.15.0 3.15.0

References

CVSS score 8.8/10
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Weakness (CWE)
CWE-502
Platform
Python (PyPI)
Package
mlflow
Disclosed
01.09.2026
Updated
11.10.2026 15:17

Sources and licenses

OSV / GitHub Advisory Database - GHSA-gqvg-gmmx-x4hm - CC BY 4.0

Vulnerability history: mlflow

All published vulnerabilities of this package (Python (PyPI)), newest first. Shows whether this is a one-off slip or a package that needs watching.

All (82) in the archive
Total entries
82
First → latest
02.2022 09.2026
Without a fix
18
Exploited in attacks
1

Severity breakdown

  • Critical 20
  • High 48
  • Medium 13
  • Low 1

Disclosures per year

  1. 2022: 1
  2. 2023: 22
  3. 2024: 24
  4. 2025: 8
  5. 2026: 27
Severity:
  1. MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False safety control bypassed by mlflow.statsmodels flavor — RCE via crafted model artifact this entry
    High · 8.8 ghsa-gqvg-gmmx-x4hm >= 2.1.0, < 3.15.0 3.15.0
  2. High · 7.1 CVE-2026-71211 >= 3.13.0, <= 3.15.2 no fix
  3. High · 8.1 CVE-2026-8147 >= 2.14.0rc0, < 3.13.0rc0 3.13.0rc0
  4. High · 7.0 CVE-2026-4137 >= 1.26.0, < 3.11.0 3.11.0
  5. Critical · 10.0 CVE-2025-15379 < 3.8.1 3.8.1
  6. Critical · 9.6 CVE-2025-15036 < 3.9.0rc0 3.9.0rc0
  7. High · 8.1 CVE-2025-15381 <= 3.8.1 no fix
  8. High · 8.1 CVE-2025-15031 < 3.9.0rc0 3.9.0rc0
  9. High · 7.5 CVE-2025-14287 < 3.8.0rc0 3.8.0rc0
  10. Critical · 9.8 CVE-2026-2635 < 3.8.0rc0 3.8.0rc0
  11. High · 7.0 CVE-2025-10279 < 3.4.0rc0 3.4.0rc0
  12. High · 8.1 CVE-2025-11200 < 2.22.0rc0 2.22.0rc0
  13. High · 8.1 CVE-2025-11201 < 2.22.4, >= 3.0.0rc0, < 3.0.0 2.22.4, 3.0.0
  14. High · 7.5 CVE-2024-8859 < 2.17.0rc0 2.17.0rc0
  15. High · 8.8 CVE-2024-37061 >= 1.11.0, <= 2.13.1 no fix
  16. High · 8.8 CVE-2024-37057 >= 2.0.0rc0, <= 2.14.1 no fix
  17. High · 8.8 CVE-2024-37058 >= 2.5.0, <= 2.14.1 no fix
  18. High · 8.8 CVE-2024-37060 >= 1.27.0, <= 2.14.1 no fix
  19. High · 8.8 CVE-2024-37059 >= 0.5.0, <= 3.4.0 no fix
  20. High · 8.8 CVE-2024-37054 >= 0.9.0, <= 2.14.1 no fix
  21. High · 8.8 CVE-2024-37052 >= 1.1.0, <= 2.14.1 no fix
  22. High · 8.8 CVE-2024-37055 >= 1.24.0, <= 2.14.1 no fix
  23. High · 8.8 CVE-2024-37056 >= 1.23.0, <= 2.14.1 no fix
  24. High · 8.8 CVE-2024-37053 >= 1.1.0, <= 2.14.1 no fix
  25. High · 8.1 CVE-2024-1560 <= 2.9.2 no fix
  26. High · 7.5 CVE-2024-1594 <= 2.9.2 no fix
  27. High · 7.5 CVE-2024-1593 <= 2.9.2 no fix
  28. High · 7.5 CVE-2024-1558 < 2.12.1 2.12.1
  29. High · 7.5 CVE-2024-1483 < 2.12.1 2.12.1
  30. High · 8.8 CVE-2023-6976 < 2.9.2 2.9.2
  31. High · 7.5 CVE-2023-6977 < 2.9.2 2.9.2
  32. Critical · 9.8 CVE-2023-6974 < 2.9.2 2.9.2
  33. Critical · 9.8 CVE-2023-6975 < 2.9.2 2.9.2
  34. High · 8.8 CVE-2023-6940 < 2.9.2 2.9.2
  35. High · 7.5 CVE-2023-43472 < 2.9.0 2.9.0
  36. Critical · 10.0 CVE-2023-6015 < 2.8.1 2.8.1
  37. Critical · 10.0 CVE-2023-6018 < 2.9.2 2.9.2
  38. High · 8.2 CVE-2022-0736 < 1.23.1 1.23.1

Know which vulnerabilities affect your application

With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.

Connect your application
DockRay newsletter

Application security in your inbox

Important vulnerabilities, actionable guidance and practical advice for your applications. Choose your technologies and follow what matters to your project.

  • A daily digest of new vulnerabilities, critical ones included.
  • Notifications about important updates.
  • Practical advice on application security and monitoring.

Leave empty to receive updates for every technology.

Free to subscribe. Unsubscribe with one click in any email.