Back to Intelligence

ZDI-26-845: MLflow Statsmodels Deserialization Flaw (CVE-2024-37052) — Detection and Remediation Guide

SA
Security Arsenal Team
October 31, 2026
10 min read

The Zero Day Initiative has published ZDI-26-845, a new advisory covering a deserialization-of-untrusted-data vulnerability in MLflow, the widely deployed open-source platform for managing machine learning lifecycles. The flaw — tracked as CVE-2024-37052 and rated CVSS 7.8 — lives in the statsmodels flavor's _load_model function and allows a remote attacker to achieve arbitrary code execution on the MLflow server. Exploitation requires user interaction: a target must open a malicious file or visit a malicious page that triggers loading of a weaponized model artifact.

Why should defenders care in 2026? Because MLflow is no longer a niche data-science tool — it sits at the center of enterprise MLOps pipelines, often running with broad network reach into training clusters, model registries, artifact stores (S3, Azure Blob, NFS), and CI/CD systems. A code-execution primitive on an MLflow tracking server is a beachhead into your entire AI/ML supply chain. The fact that ZDI is publishing a formal advisory on this issue now means the technical details — and with them, the barrier to weaponization — are dropping. If your organization runs MLflow, treat this as an urgent patch-and-hunt event.

Technical Analysis

Affected Component

The vulnerability resides in MLflow's statsmodels flavor, specifically the _load_model function. MLflow "flavors" are pluggable serialization/deserialization modules that let data scientists save and reload models from dozens of frameworks (scikit-learn, PyTorch, TensorFlow, statsmodels, etc.). When a statsmodels model is loaded, _load_model deserializes the persisted artifact — and here is the core problem: it does so without validating the provenance or integrity of the input.

Root Cause: Deserialization of Untrusted Data (CWE-502)

Python's serialization ecosystem is the recurring offender. Statsmodels models are commonly persisted via pickle (or pickle-derived mechanisms like joblib and cloudpickle). Python pickle is fundamentally unsafe for untrusted input: during unpickling, the __reduce__ protocol can invoke arbitrary callables with attacker-controlled arguments. An attacker who can get a maliciously crafted model artifact loaded by _load_model gains code execution in the context of the MLflow process — typically a service account with access to the tracking database, artifact store credentials, and internal network segments.

Attack Chain (Defender's View)

  1. Delivery: Attacker crafts a malicious statsmodels model artifact (a pickled object containing a malicious __reduce__ payload) and gets a victim to interact with it — e.g., via a malicious page or file that causes the artifact to be registered/loaded through MLflow.
  2. Load: _load_model deserializes the artifact without provenance checks.
  3. Execution: The embedded payload executes — typically spawning a child process (shell, Python one-liner, or downloader) from the MLflow server process.
  4. Post-exploitation: The attacker harvests artifact-store credentials, pivots into training infrastructure, or poisons the model registry itself — a supply-chain nightmare where downstream consumers pull backdoored models.

Severity and Exploitation Status

  • CVSS: 7.8 (High). The user-interaction requirement tempers the score, but in MLOps environments "user interaction" is routine — data scientists open and load shared model artifacts constantly.
  • Authentication: The advisory characterizes the flaw as enabling unauthenticated code execution paths once interaction occurs — meaning no valid MLflow credential is needed on the attacker's side of the transaction.
  • Exploitation status: This is a publicly documented ZDI advisory, which historically correlates with PoC availability following disclosure. Defenders should assume weaponization is trivial given how well-understood Python pickle exploitation is. At time of writing, verify current status against the CISA KEV catalog and the ZDI advisory page.

Detection & Response

The most reliable observable for this class of flaw is the MLflow server process spawning unexpected child processes. A healthy MLflow tracking server does not spawn shells, downloaders, or network utilities. That signal is high-fidelity and survives payload changes.

YAML
---
title: MLflow Process Spawning Suspicious Child Process
id: 3b8f2a41-7c9d-4e1a-b6f2-9d5c1a8e4f07
status: experimental
description: Detects the MLflow server process (mlflow/gunicorn/flask) spawning shells, interpreters, or download utilities — consistent with deserialization RCE such as CVE-2024-37052 in the statsmodels _load_model flavor.
references:
  - http://www.zerodayinitiative.com/advisories/ZDI-26-845/
  - https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.execution
  - attack.t1059
  - attack.t1190
logsource:
  category: process_creation
  product: linux
detection:
  selection_parent:
    ParentImage|endswith:
      - '/mlflow'
      - '/gunicorn'
      - '/flask'
      - '/python'
      - '/python3'
  selection_child:
    Image|endswith:
      - '/bash'
      - '/sh'
      - '/dash'
      - '/zsh'
      - '/curl'
      - '/wget'
      - '/nc'
      - '/ncat'
      - '/socat'
      - '/base64'
      - '/python'
      - '/python3'
      - '/perl'
  condition: selection_parent and selection_child
falsepositives:
  - MLflow deployments that legitimately shell out during model loading (rare); tune the parent image to your exact MLflow service path
level: high
---
title: Python Deserialization Payload via Pickle Opcodes in Command Line
id: 6e1c9d05-2a4b-4f38-9c71-5b3a7d2e8f19
status: experimental
description: Detects common pickle/cloudpickle exploitation primitives appearing in process command lines, including os.system, subprocess, and base64-encoded payloads staged through Python.
references:
  - http://www.zerodayinitiative.com/advisories/ZDI-26-845/
  - https://attack.mitre.org/techniques/T1059.006/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.execution
  - attack.t1059.006
logsource:
  category: process_creation
  product: linux
detection:
  selection_img:
    Image|endswith:
      - '/python'
      - '/python3'
  selection_cli:
    CommandLine|contains:
      - '__reduce__'
      - 'os.system('
      - 'subprocess.Popen'
      - 'subprocess.call'
      - 'pickle.loads'
      - 'cloudpickle'
      - 'cStringIO'
      - '/dev/tcp/'
      - 'socket.socket'
  condition: selection_img and selection_cli
falsepositives:
  - Legitimate data-science scripts; scope to MLflow server hosts and artifact-processing workers
level: medium
---
title: MLflow Artifact Store Write of Suspicious Model Files
id: 9d4e7b28-5f16-4a03-bc84-2e7a1c9f3d56
status: experimental
description: Detects creation of pickled model artifacts in MLflow artifact directories by processes other than the MLflow service, which may indicate an attacker staging a malicious statsmodels model for deserialization.
references:
  - http://www.zerodayinitiative.com/advisories/ZDI-26-845/
  - https://attack.mitre.org/techniques/T1195/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.initial_access
  - attack.t1195
logsource:
  category: file_event
  product: linux
detection:
  selection_path:
    TargetFilename|contains:
      - '/mlruns/'
      - '/mlartifacts/'
      - '/mlflow-artifacts/'
  selection_ext:
    TargetFilename|endswith:
      - '.pkl'
      - '.pickle'
      - '.joblib'
      - 'model.pkl'
  filter_service:
    Image|endswith:
      - '/mlflow'
      - '/gunicorn'
  condition: selection_path and selection_ext and not filter_service
falsepositives:
  - Data scientists manually copying models into artifact stores — a practice that should be eliminated anyway
level: medium
KQL — Microsoft Sentinel / Defender
// Hunt: MLflow server processes spawning shells, downloaders, or interpreters
// Ingest Linux auditd/Sysmon-for-Linux via Syslog or Defender for Endpoint
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where InitiatingProcessFileName has_any ("mlflow", "gunicorn", "flask")
   or InitiatingProcessCommandLine has_any ("mlflow server", "mlflow ui", "mlflow models serve")
| where FileName has_any ("bash", "sh", "dash", "curl", "wget", "nc", "ncat", "socat", "perl")
   or ProcessCommandLine has_any ("/dev/tcp/", "base64 -d", "os.system", "subprocess", "pickle.loads", "__reduce__")
| project TimeGenerated, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine,
          FileName, ProcessCommandLine, AccountName, RemoteIP, RemoteUrl
| order by TimeGenerated desc
;
// Companion hunt: outbound connections from MLflow hosts to rare destinations
DeviceNetworkEvents
| where TimeGenerated > ago(7d)
| where InitiatingProcessFileName has_any ("mlflow", "gunicorn")
| where RemotePort !in (443, 80, 5000, 8080)  // tune to your approved egress
| summarize ConnectionCount = count(), Destinations = make_set(RemoteIP) by DeviceName, InitiatingProcessFileName
| order by ConnectionCount desc
VQL — Velociraptor
-- Artifact: Hunt.MLflow.DeserializationRCE
-- Identifies suspicious child processes of MLflow servers and recently
-- created pickled model artifacts in MLflow artifact directories.

-- Section 1: MLflow processes and their children
SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE CommandLine =~ 'mlflow|gunicorn'
   OR Exe =~ '(bash|sh|curl|wget|nc|ncat|socat)$'

-- Section 2: Staged pickled artifacts in MLflow model directories
SELECT FullPath, Size, Mtime, Atime
FROM glob(globs=['/**/mlruns/**/*.pkl', '/**/mlartifacts/**/*.pkl', '/**/mlflow-artifacts/**/*.pkl', '/**/mlruns/**/*.joblib'])
WHERE Mtime > (now() - 604800)  -- created/modified in the last 7 days
ORDER BY Mtime DESC

-- Section 3: Unexpected listening or outbound sockets owned by MLflow
SELECT Pid, Name, Family, Type, Status, Laddr, Lport, Raddr, Rport
FROM netstat()
WHERE Name =~ 'mlflow|gunicorn|python'
  AND Status =~ 'ESTABLISHED'
  AND Rport NOT IN (80, 443, 5000, 8080)
Bash / Shell
#!/usr/bin/env bash
# mlflow-cve-2024-37052-audit.sh
# Audit and harden MLflow deployments against statsmodels _load_model deserialization RCE
set -euo pipefail

echo "=== [1] Identify running MLflow processes and versions ==="
ps aux | grep -Ei 'mlflow|gunicorn' | grep -v grep || echo "No MLflow processes found"

echo ""
echo "=== [2] Report installed MLflow and statsmodels versions ==="
python3 -m pip show mlflow statsmodels 2>/dev/null | grep -E '^(Name|Version|Location)' || \
  echo "pip metadata not found on this host — check your virtualenvs and container images"

echo ""
echo "=== [3] Scan common virtualenvs/containers for vulnerable mlflow packages ==="
find / -maxdepth 6 -type d -name 'mlflow' -path '*site-packages*' 2>/dev/null | while read -r d; do
  ver=$(grep -m1 '^__version__' "$d/version.py" 2>/dev/null || echo 'unknown')
  echo "FOUND: $d  ($ver)"
done

echo ""
echo "=== [4] Check whether the statsmodels flavor path exists (attack surface present) ==="
find / -maxdepth 7 -type f -name 'statsmodels' -path '*mlflow*' 2>/dev/null | head -20
find / -maxdepth 8 -type d -path '*mlflow/statsmodels*' 2>/dev/null | head -20

echo ""
echo "=== [5] Audit recently modified pickled artifacts in MLflow stores ==="
find / -maxdepth 8 \( -path '*mlruns*' -o -path '*mlartifacts*' -o -path '*mlflow-artifacts*' \) \
  -type f \( -name '*.pkl' -o -name '*.pickle' -o -name '*.joblib' \) \
  -mtime -7 -exec ls -la {} \; 2>/dev/null | head -50

echo ""
echo "=== [6] Verify MLflow is NOT exposed unauthenticated ==="
ss -tlnp 2>/dev/null | grep -E ':(5000|5001|8080)' || echo "No default MLflow ports listening"

echo ""
echo "=== REMEDIATION ==="
echo "1) Upgrade MLflow to the latest patched release:"
echo "     python3 -m pip install --upgrade mlflow"
echo "2) Rebuild all container images embedding MLflow (do not patch in place)."
echo "3) Restrict artifact loading: never load models from untrusted/unauthenticated sources."
echo "4) Place MLflow behind SSO/reverse proxy auth and network-segment it from general user VLANs."

Remediation

  1. Patch immediately. Upgrade MLflow to the latest maintained release across every deployment — tracking servers, model-serving endpoints, training notebooks, CI runners, and especially container images (rebuild, don't patch in place). Review the ZDI advisory and the MLflow GitHub security advisories for the fixed-version mapping for CVE-2024-37052, and check the CISA KEV catalog for any mandated remediation deadline.

  2. Enforce artifact provenance. The structural fix for CWE-502 in MLOps is: never deserialize models from untrusted sources. Require signed model artifacts, gate registry writes behind authenticated CI identities, and scan all inbound artifacts. Where possible, prefer safer serialization formats (e.g., ONNX, safetensors) over raw pickle for statsmodels and other flavors.

  3. Harden the MLflow attack surface. MLflow ships with minimal authentication by default. Put the tracking server behind an authenticated reverse proxy (OIDC/SSO), disable unauthenticated artifact upload/download, bind to internal interfaces only, and run the service as a low-privilege, containerized workload with restricted egress.

  4. Isolate the blast radius. Network-segment MLflow infrastructure from general user VLANs and from production data stores. Apply egress filtering so a compromised tracking server cannot reach the internet or crown-jewel systems. Rotate any cloud/artifact-store credentials the MLflow service can access if you find suspicious process activity.

  5. Hunt retroactively. Run the KQL and VQL hunts above across at least 30 days of telemetry. Any shell or downloader spawned by an MLflow process is a full IR trigger — assume registry poisoning and audit every model artifact loaded downstream since the event.

  6. Educate the humans in the loop. Exploitation requires a user to open a malicious file or page. Brief your data-science and ML engineering teams specifically: do not load shared or externally sourced model artifacts into production MLflow instances, and treat unsolicited model files like you treat macro-enabled Office documents.

Related Resources

Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.