CVE-2026-31238: Ludwig: RCE via unsafe pickle deserialization in model serve

AWAITING NVD
Published May 12, 2026
CISO Take

Ludwig's model serving command loads PyTorch model files using `torch.load()` without the `weights_only=True` parameter, meaning any model file deserialized at startup has unrestricted Python pickle execution capabilities — a well-understood, trivially exploitable primitive for achieving arbitrary code execution. This affects any team running `ludwig serve` in production or staging environments, particularly in MLOps pipelines that automatically pull and serve models from shared registries or external sources. While no EPSS score or active exploitation has been recorded yet, pickle-based RCE in ML tooling is a heavily documented and tooled attack class requiring minimal attacker sophistication. Immediate action: do not load Ludwig models from untrusted or unverified sources, audit model file provenance controls, and use `fickling` or `picklescan` to inspect model files; upgrade Ludwig once a patched release is available.

Sources: NVD ATLAS GitHub Advisory

Risk Assessment

High risk despite absent CVSS data. Pickle deserialization RCE is a known-high-severity class — CVSS typically lands 9.8 for network-reachable unauthenticated variants. The attack surface is the model server process, which may be internet-facing or accessible to internal shared storage. Exploitation requires only that an attacker can place a malicious model file in the path Ludwig loads from — no authentication needed against the framework itself. The `weights_only=True` parameter exists precisely to prevent this class of attack; omitting it is a well-known insecure default in PyTorch ecosystems.

Attack Kill Chain

Artifact Weaponization
Adversary generates a malicious PyTorch model file with an embedded pickle payload using publicly available tooling such as fickling or a custom Python script.
AML.T0011.000
Malicious Model Delivery
The crafted model file is placed in a location accessible to the target's Ludwig deployment — a shared model registry, S3 bucket, NFS mount, or via an MLOps API that accepts model uploads.
AML.T0010.003
Insecure Deserialization Trigger
The victim runs `ludwig serve --model-path <malicious.pt>`; Ludwig calls torch.load() without weights_only=True, causing the pickle payload to deserialize and execute.
AML.T0049
Arbitrary Code Execution
Adversary's payload executes with the model server process's OS privileges, enabling reverse shell establishment, credential theft, or lateral movement into internal infrastructure.
AML.T0018.002

Severity & Risk

CVSS 3.1
N/A
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
Trivial

Recommended Action

5 steps
  1. Upgrade Ludwig to a version beyond 0.10.4 once a patched release is published — monitor the Ludwig GitHub repository for a fix that enforces weights_only=True.

  2. Immediate workaround: restrict model file sources strictly to internally-signed, provenance-tracked artifacts; never load externally-supplied or user-provided .pt/.ckpt files.

  3. Scan all PyTorch model files with fickling (Trail of Bits) or picklescan before loading — both detect embedded pickle payloads.

  4. Migrate model storage to SafeTensors format (CWE-502-immune by design) where the pipeline permits.

  5. Apply least-privilege to the model server process — run in a restricted container with no cloud metadata access, minimal network egress, and no write access to secrets.

Classification

Compliance Impact

This CVE is relevant to:

EU AI Act
Art. 15 - Accuracy, robustness and cybersecurity
ISO 42001
A.6.2.6 - AI system supply chain
NIST AI RMF
MS-2.5 - AI risks and impacts are monitored
OWASP LLM Top 10
LLM03:2025 - Supply Chain Vulnerabilities

Frequently Asked Questions

What is CVE-2026-31238?

Ludwig's model serving command loads PyTorch model files using `torch.load()` without the `weights_only=True` parameter, meaning any model file deserialized at startup has unrestricted Python pickle execution capabilities — a well-understood, trivially exploitable primitive for achieving arbitrary code execution. This affects any team running `ludwig serve` in production or staging environments, particularly in MLOps pipelines that automatically pull and serve models from shared registries or external sources. While no EPSS score or active exploitation has been recorded yet, pickle-based RCE in ML tooling is a heavily documented and tooled attack class requiring minimal attacker sophistication. Immediate action: do not load Ludwig models from untrusted or unverified sources, audit model file provenance controls, and use `fickling` or `picklescan` to inspect model files; upgrade Ludwig once a patched release is available.

Is CVE-2026-31238 actively exploited?

No confirmed active exploitation of CVE-2026-31238 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-31238?

1. Upgrade Ludwig to a version beyond 0.10.4 once a patched release is published — monitor the Ludwig GitHub repository for a fix that enforces `weights_only=True`. 2. Immediate workaround: restrict model file sources strictly to internally-signed, provenance-tracked artifacts; never load externally-supplied or user-provided `.pt`/`.ckpt` files. 3. Scan all PyTorch model files with `fickling` (Trail of Bits) or `picklescan` before loading — both detect embedded pickle payloads. 4. Migrate model storage to SafeTensors format (CWE-502-immune by design) where the pipeline permits. 5. Apply least-privilege to the model server process — run in a restricted container with no cloud metadata access, minimal network egress, and no write access to secrets.

What systems are affected by CVE-2026-31238?

This vulnerability affects the following AI/ML architecture patterns: model serving, ML inference pipelines, MLOps pipelines, model registries, training pipelines.

What is the CVSS score for CVE-2026-31238?

No CVSS score has been assigned yet.

Technical Details

NVD Description

The Ludwig framework thru 0.10.4 is vulnerable to insecure deserialization (CWE-502) in its model serving component. When starting a model server with the ludwig serve command, the framework loads model weight files using torch.load() without enabling the security-restrictive weights_only=True parameter. This default behavior allows the deserialization of arbitrary Python objects via the pickle module. An attacker can exploit this by providing a maliciously crafted PyTorch model file, leading to arbitrary code execution on the system hosting the Ludwig model server.

Exploitation Scenario

An adversary targeting an organization using Ludwig for model serving generates a malicious PyTorch model file using publicly available tools (e.g., `fickling` in write mode or a custom pickle payload) that embeds a reverse shell or credential exfiltration command. The attacker uploads this file to a shared model registry, S3 bucket with misconfigured permissions, or submits it via an MLOps API that accepts model uploads. When the victim's automated pipeline runs `ludwig serve --model-path <malicious.pt>`, `torch.load()` deserializes the pickle payload without restriction, executing the adversary's code with the server process's privileges — granting lateral movement into internal systems or cloud infrastructure.

Timeline

Published
May 12, 2026
Last Modified
May 12, 2026
First Seen
May 12, 2026

Related Vulnerabilities