GHSA-gqvg-gmmx-x4hm
GHSA-gqvg-gmmx-x4hm · MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False safety control bypassed by mlflow.statsmodels flavor — RCE via crafted model artifact
Cette page présente des faits issus de sources publiques. Consultez l’avis original avant toute mise à jour.
## 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**: ``` # 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`): - https://github.com/mlflow/mlflow/blob/0b0c576c642b5b0d9496c829809c7d097403bc9f/mlflow/statsmodels/__init__.py#L307-L310 - https://github.com/mlflow/mlflow/blob/0b0c576c642b5b0d9496c829809c7d097403bc9f/mlflow/statsmodels/__init__.py#L313-L320 --- ## Recommended Fix 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) ```
CVSS 8.8 · Élevée · Correctif disponible
- Publication
- Mise à jour
Pile logicielle: python
Produits et versions concernés
mlflow PyPI
- Versions du logiciel
- 2.1.0
- 2.1.1
- 2.10.0
- 2.10.1
- 2.10.2
- 2.11.0
- 2.11.1
- 2.11.2
- 2.11.3
- 2.11.4
- 2.12.0
- 2.12.1
- 2.12.2
- 2.13.0
- 2.13.1
- 2.13.2
- 2.14.0
- 2.14.0rc0
- 2.14.1
- 2.14.2
- 2.14.2.dev0
- 2.14.3
- 2.15.0
- 2.15.0rc0
- 2.15.1
- 2.16.0
- 2.16.1
- 2.16.2
- 2.17.0
- 2.17.0rc0
- 2.17.1
- 2.17.2
- 2.18.0
- 2.18.0rc0
- 2.19.0
- 2.19.0rc0
- 2.2.0
- 2.2.1
- 2.2.2
- 2.20.0
- 2.20.0rc0
- 2.20.1
- 2.20.2
- 2.20.3
- 2.20.4
- 2.21.0
- 2.21.0rc0
- 2.21.1
- 2.21.2
- 2.21.3
- 2.22.0
- 2.22.0rc0
- 2.22.1
- 2.22.2
- 2.22.3
- 2.22.4
- 2.22.5
- 2.3.0
- 2.3.1
- 2.3.2
- 2.4.0
- 2.4.1
- 2.4.2
- 2.5.0
- 2.6.0
- 2.7.0
- 2.7.1
- 2.8.0
- 2.8.1
- 2.9.0
- 2.9.1
- 2.9.2
- 3.0.0
- 3.0.0rc0
- 3.0.0rc1
- 3.0.0rc2
- 3.0.0rc3
- 3.0.1
- 3.1.0
- 3.1.0rc0
- 3.1.1
- 3.1.2
- 3.1.3
- 3.1.4
- 3.10.0
- 3.10.0rc0
- 3.10.1
- 3.11.0
- 3.11.0rc0
- 3.11.0rc1
- 3.11.1
- 3.12.0
- 3.12.0rc0
- 3.13.0
- 3.13.0rc0
- 3.14.0
- 3.2.0
- 3.2.0rc0
- 3.3.0
- 3.3.0rc0
- 3.3.1
- 3.3.2
- 3.4.0
- 3.4.0rc0
- 3.5.0
- 3.5.0rc0
- 3.5.1
- 3.6.0
- 3.6.0rc0
- 3.7.0
- 3.7.0rc0
- 3.8.0
- 3.8.0rc0
- 3.8.1
- 3.9.0
- 3.9.0rc0
- Plages de versions concernées
- ECOSYSTEM: ≥ 2.1.0, < 3.15.0
Mettez à jour vers 3.15.0
Sources originales
- https://github.com/mlflow/mlflow/security/advisories/GHSA-gqvg-gmmx-x4hm
- https://github.com/mlflow/mlflow/pull/24686
- https://github.com/mlflow/mlflow/commit/38615289094a4b700a20b5d1dbfbe57bdfb0411f
- https://github.com/mlflow/mlflow
- https://github.com/mlflow/mlflow/releases/tag/v3.15.0
- https://osv.dev/vulnerability/GHSA-gqvg-gmmx-x4hm