Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2025-54886

CVE-2025-54886: skops Python Library RCE Vulnerability

CVE-2025-54886 is a remote code execution flaw in skops Python library that allows arbitrary code execution through unsafe joblib fallback. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2025-54886 Overview

CVE-2025-54886 is an insecure deserialization vulnerability in skops, a Python library used to share and ship scikit-learn based machine learning models. The flaw resides in the Card.get_model function, which supports both joblib and skops formats for model loading. When a non-.zip file is provided, the function silently falls back to joblib, which permits arbitrary code execution during deserialization. This behavior bypasses the trusted-type validation that the .skops loader enforces. The issue affects versions 0.12.0 and below and is fixed in version 0.13.0.

Critical Impact

An attacker who can supply a model file to a victim using Card.get_model can achieve arbitrary code execution under the victim's user context with no user interaction.

Affected Products

  • skops Python library versions 0.12.0 and earlier
  • Applications and pipelines invoking Card.get_model on untrusted model files
  • Machine learning workflows using joblib-format model artifacts via skops Card

Discovery Timeline

  • 2025-08-08 - CVE-2025-54886 published to NVD
  • 2026-04-15 - Last updated in NVD database

Technical Details for CVE-2025-54886

Vulnerability Analysis

The vulnerability is classified as Insecure Deserialization [CWE-502]. The skops Card.get_model function is designed to load serialized scikit-learn models from disk. When the input file uses the .skops (.zip) format, the library invokes its hardened loader that validates object types against a trusted-types allowlist and raises errors for unknown types. When the input does not match the .zip container, the function silently delegates loading to joblib without warning the caller. joblib is built on Python's pickle protocol, which executes arbitrary callables embedded in the serialized stream during reconstruction. A crafted model file therefore turns model loading into code execution.

Root Cause

The root cause is an unsafe fallback path in _load_model. The function did not expose a user-controlled flag to gate pickle-based loading, and it did not emit a warning when downgrading from skops' trusted loader to joblib. Callers expecting the safety guarantees documented for .skops files instead received pickle's execute-on-load semantics for any other extension.

Attack Vector

Exploitation requires the victim to call Card.get_model on an attacker-supplied file that is not a valid .skops zip archive. The file can be delivered through model marketplaces, shared notebooks, repository check-ins, or supply chain compromise of upstream model artifacts. Successful exploitation yields execution with the privileges of the Python process loading the model.

python
# Security patch in skops/card/_model_card.py
# Source: https://github.com/skops-dev/skops/commit/29d61ea8a92f2bde6830e8f32cc72a1a87211cda

-def _load_model(model: Any, trusted=False) -> Any:
+def _load_model(
+    model: Any, trusted: Optional[Sequence[str]] = None, allow_pickle: bool = False
+) -> Any:
     """Return a model instance.

     Loads the model if provided a file path, if already a model instance return

The patch introduces an explicit allow_pickle parameter that defaults to False, forcing callers to opt in before any joblib/pickle deserialization occurs. See the skops security advisory GHSA-378x-6p4f-8jgm for additional detail.

Detection Methods for CVE-2025-54886

Indicators of Compromise

  • Python processes spawning unexpected child processes (sh, bash, cmd.exe, powershell.exe) immediately after a model-loading call.
  • Inbound model files with non-.skops extensions (.pkl, .joblib, .bin) sourced from external or untrusted repositories.
  • Outbound network connections initiated by ML training or inference jobs that previously had no egress profile.
  • New cron jobs, scheduled tasks, or persistence artifacts created by accounts running ML pipelines.

Detection Strategies

  • Inventory all installations of skops and flag versions <= 0.12.0 across developer endpoints, CI runners, and inference servers.
  • Hunt source repositories and notebooks for calls to Card.get_model that pass file paths not ending in .skops.
  • Alert on joblib.load or pickle.load invocations originating from data science workloads handling externally sourced files.
  • Correlate process-execution telemetry to identify Python interpreters spawning shells or compilers within seconds of file reads against model artifact directories.

Monitoring Recommendations

  • Log and review file pulls of model artifacts from registries such as Hugging Face, S3, and internal MLflow stores.
  • Monitor module import telemetry for unexpected loads triggered during deserialization (for example, os, subprocess, socket).
  • Track exceptions and warnings emitted by skops loaders to surface fallback behavior in production code paths.

How to Mitigate CVE-2025-54886

Immediate Actions Required

  • Upgrade skops to version 0.13.0 or later across all environments that load model files.
  • Audit code for calls to Card.get_model and pass allow_pickle=False (the new default) unless pickle-based loading is explicitly required and the source is trusted.
  • Quarantine and re-validate any model artifacts received from external parties since deployment of skops <= 0.12.0.
  • Re-issue credentials and tokens accessible to processes that previously loaded untrusted model files.

Patch Information

The fix is delivered in skops 0.13.0 via commit 29d61ea8. The patch refactors _load_model to accept an allow_pickle flag (default False) and requires callers to opt in before any non-.skops file is dispatched to joblib. Details are published in GHSA-378x-6p4f-8jgm.

Workarounds

  • Restrict model loading to files using the .skops (.zip) format and reject other extensions at the application layer.
  • Execute model-loading code in sandboxed, network-restricted containers with least-privilege service accounts.
  • Enforce cryptographic signing and verification of model artifacts before they reach Card.get_model.
  • Block ingestion of pickle-based model formats (.pkl, .joblib) from untrusted sources via repository and proxy policy.
bash
# Configuration example: upgrade skops and pin a safe minimum version
pip install --upgrade 'skops>=0.13.0'

# Verify installed version
python -c "import skops; print(skops.__version__)"

# Example safe usage pattern
python -c "from skops.card import Card; c = Card.load('model_card'); c.get_model(allow_pickle=False)"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.