
PEACH
Un cadre d’isolation des locataires
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.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:
# 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."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.0With 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")--app-name basic-auth), authentication is disabled, so artifact upload requires no credentials.mlflow/statsmodels/__init__.py L307-310: _load_model — calls smio.load_pickle without checking MLFLOW_ALLOW_PICKLE_DESERIALIZATIONmlflow/statsmodels/__init__.py L313-320: _load_pyfunc — dispatches to _load_model without checking the control
Permalink (commit 0b0c576c):Add the missing guard to mlflow/statsmodels/__init__.py:
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)Source: NVD
Évaluation gratuite des vulnérabilités
Évaluez vos pratiques de sécurité cloud dans 9 domaines de sécurité pour évaluer votre niveau de risque et identifier les failles dans vos défenses.
Obtenez une démo personnalisée
"La meilleure expérience utilisateur que j’ai jamais vue, offre une visibilité totale sur les workloads cloud."
"Wiz fournit une interface unique pour voir ce qui se passe dans nos environnements cloud."
"Nous savons que si Wiz identifie quelque chose comme critique, c’est qu’il l’est réellement."