{"answers":{"affected":"2 open source packages ship an affected version, including mlflow.","exploited":"There is no known exploitation of GHSA-gqvg-gmmx-x4hm in the wild and no public exploit code.","fix":"Upgrade mlflow to 3.15.0 or later.","what":"GHSA-gqvg-gmmx-x4hm is an unsafe deserialization vulnerability in mlflow, published on 1 Sep 2026. An attacker can exploit it over the internet without logging in, with no action from the victim."},"fix_prompt":"Check this codebase for GHSA-gqvg-gmmx-x4hm and fix it if it is affected.\n\nWhat it is: GHSA-gqvg-gmmx-x4hm is an unsafe deserialization vulnerability in mlflow, published on 1 Sep 2026. An attacker can exploit it over the internet without logging in, with no action from the victim.\nExploitation: There is no known exploitation of GHSA-gqvg-gmmx-x4hm in the wild and no public exploit code.\n\nAffected packages and fixed versions:\n- mlflow (PyPI): affected from 2.1.0; fixed in 3.15.0\n- mlflow (PyPI): affected from 2.1.0; fixed in 3.15.0\n\nTask:\n1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.\n2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.\n3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.\n4. Run the tests and summarise what changed and why.\n5. If nothing in the project is affected, say so and change nothing.\n\nReference: https://insights.sbomify.com/GHSA-gqvg-gmmx-x4hm/ (Markdown: https://insights.sbomify.com/GHSA-gqvg-gmmx-x4hm/index.md)","id":"GHSA-gqvg-gmmx-x4hm","markdown":"https://insights.sbomify.com/GHSA-gqvg-gmmx-x4hm/index.md","name":"GHSA-gqvg-gmmx-x4hm","record":{"aliases":[],"analysis":{"component_type":"library","fix_type":"patch","impacts":["code_execution","security_bypass"],"network_reachable":"yes","non_default_config":true,"product_category":"MLflow library","requires_auth":"none","summary":"Attacker achieves remote code execution via crafted model artifact, bypassing MLflow's pickle deserialization safety control in the statsmodels flavor.","user_interaction":"not_required","vuln_class":"deserialization"},"analysis_generated_by":"qwen3.8-flash-next","assigner":null,"cpe":[],"cvss":{"score":null,"severity":null,"source":null,"vector":null,"version":null},"cwes":[],"description":"## Summary\n\nMLflow 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.\n\nHowever, 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`**.\n\nThis is a security control bypass. The operator believes pickle RCE is mitigated; the statsmodels flavor silently ignores the control.\n\n---\n\n## Root Cause\n\n`mlflow.pyfunc.load_model()` dispatches to flavor `_load_pyfunc` implementations via:\n\n```\n# mlflow/pyfunc/__init__.py L1170-1172\nmodel_impl = importlib.import_module(conf[MAIN])._load_pyfunc(data_path)\n```\n\nThe guarded pattern (from `mlflow/sklearn/__init__.py` L526-533, the reference implementation) is:\n\n```\nif (\n    not MLFLOW_ALLOW_PICKLE_DESERIALIZATION.get()\n    and not is_in_databricks_runtime()\n    and not is_in_databricks_model_serving_environment()\n):\n    raise MlflowException(\"Deserializing model using pickle is disallowed...\")\n```\n\n`mlflow/statsmodels/__init__.py` has **no such check**:\n\n```\n# L307-320 — no guard anywhere in this file\ndef _load_model(path):\n    import statsmodels.iolib.api as smio\n    return smio.load_pickle(path)   # calls pickle.load() directly\n\ndef _load_pyfunc(path):\n    return _StatsmodelsModelWrapper(_load_model(path))\n```\n\n`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.\"*\n\n---\n\n## Trigger\n\nAn attacker crafts an MLmodel YAML that specifies `mlflow.statsmodels` as the loader module:\n\n```\nflavors:\n  python_function:\n    loader_module: mlflow.statsmodels\n    data: model.pkl\n  statsmodels:\n    data: model.pkl\n    statsmodels_version: 0.14.0\n```\n\nWith a malicious `model.pkl` placed alongside it in the artifact store, any call to:\n\n```\nos.environ[\"MLFLOW_ALLOW_PICKLE_DESERIALIZATION\"] = \"False\"\nmlflow.pyfunc.load_model(\"models:/MaliciousModel/1\")\n```\n\n...deserializes the pickle file with **no guard check**, executing arbitrary code with the privileges of the calling process.\n\nOn default MLflow deployments (no `--app-name basic-auth`), authentication is disabled, so artifact upload requires no credentials.\n\n---\n\n## Affected Code\n\n- `mlflow/statsmodels/__init__.py` L307-310: `_load_model` — calls `smio.load_pickle` without checking `MLFLOW_ALLOW_PICKLE_DESERIALIZATION`\n- `mlflow/statsmodels/__init__.py` L313-320: `_load_pyfunc` — dispatches to `_load_model` without checking the control\n\nPermalink (commit `0b0c576c`):\n- https://github.com/mlflow/mlflow/blob/0b0c576c642b5b0d9496c829809c7d097403bc9f/mlflow/statsmodels/__init__.py#L307-L310\n- https://github.com/mlflow/mlflow/blob/0b0c576c642b5b0d9496c829809c7d097403bc9f/mlflow/statsmodels/__init__.py#L313-L320\n\n---\n\n## Recommended Fix\n\nAdd the missing guard to `mlflow/statsmodels/__init__.py`:\n\n```\nfrom mlflow.environment_variables import MLFLOW_ALLOW_PICKLE_DESERIALIZATION\nfrom mlflow.utils.databricks_utils import (\n    is_in_databricks_model_serving_environment,\n    is_in_databricks_runtime,\n)\n\ndef _load_model(path):\n    if (\n        not MLFLOW_ALLOW_PICKLE_DESERIALIZATION.get()\n        and not is_in_databricks_runtime()\n        and not is_in_databricks_model_serving_environment()\n    ):\n        raise MlflowException(\n            \"Deserializing model using pickle is disallowed, but this statsmodels \"\n            \"model requires pickle deserialization. Set environment variable \"\n            \"'MLFLOW_ALLOW_PICKLE_DESERIALIZATION' to 'true' to allow this.\"\n        )\n    import statsmodels.iolib.api as smio\n    return smio.load_pickle(path)\n```","ecosystems":["PyPI"],"exploits":{"exploitdb":null,"first_seen":null,"github_poc":null,"max_poc_stars":null,"metasploit":null,"nuclei":null,"refs":[],"tier":null},"has_fix":true,"headline":"MLflow introduced `MLFLOW_ALLOW_PICKLE_DESERIALIZATION` as a security control to prevent unsafe `pickle.load` execution during mo","id":"GHSA-gqvg-gmmx-x4hm","indexable":true,"kev":null,"kind":"advisory","links":{"ecosystem":"PyPI","product":null,"products":[],"type":"deserialization","year":"2026"},"n_packages":2,"n_references":null,"packages":[{"ecosystem":"PyPI","fixed":["3.15.0"],"introduced":["2.1.0"],"last_affected":[],"package":"mlflow","purl":null,"source":"GHSA-gqvg-gmmx-x4hm"},{"ecosystem":"PyPI","fixed":["3.15.0"],"introduced":["2.1.0"],"last_affected":[],"package":"mlflow","purl":"pkg:pypi/mlflow","source":"GHSA-gqvg-gmmx-x4hm"}],"products":null,"published":"2026-09-01","related":[],"sources":[{"class":"attribution","licence":"CC BY 4.0","name":"GitHub Advisory Database","prefix":"GHSA"}],"ssvc":{"automatable":null,"exploitation":null,"technical_impact":null},"state":null,"updated":null,"vendors":null},"summary":"Attacker achieves remote code execution via crafted model artifact, bypassing MLflow's pickle deserialization safety control in the statsmodels flavor.","url":"https://insights.sbomify.com/GHSA-gqvg-gmmx-x4hm/"}