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

CVE-2025-54412: skops Python Library RCE Vulnerability

CVE-2025-54412 is a remote code execution flaw in the skops Python library that allows attackers to exploit OperatorFuncNode inconsistencies for arbitrary code execution. This article covers technical details, affected versions, and mitigations.

Published:

CVE-2025-54412 Overview

CVE-2025-54412 affects skops, a Python library used to share and ship scikit-learn based machine learning models. The vulnerability resides in the OperatorFuncNode component, where an inconsistency in the audit logic lets attackers hide the execution of untrusted operator methods. An attacker can chain this flaw into a code reuse attack, invoking seemingly safe functions to escalate to arbitrary code execution. The malicious payload appears to require only minimal and misleading trusted types, defeating the library's safety model. This issue is classified under CWE-351: Insufficient Type Distinction and impacts skops versions 0.11.0 and below. The maintainers fixed the issue in version 0.12.0.

Critical Impact

An attacker who convinces a user to load a crafted skops model file can achieve arbitrary code execution while bypassing the trusted-types audit that users rely on for safety.

Affected Products

  • skops Python library versions 0.11.0 and below
  • Workflows that load untrusted skops-serialized scikit-learn models
  • Applications using OperatorFuncNode and MethodNode audit paths prior to v0.12.0

Discovery Timeline

  • 2025-07-26 - CVE-2025-54412 published to NVD
  • 2026-06-17 - Last updated in NVD database

Technical Details for CVE-2025-54412

Vulnerability Analysis

The skops library implements a custom serialization format intended to be safer than Python's pickle by auditing which types and functions a model is allowed to invoke at load time. Users approve a set of trusted types, and the loader rejects nodes that reference anything outside that set. The flaw in OperatorFuncNode breaks this guarantee. The node audits one representation of the operator while executing a different one, so the function actually invoked is never checked against the user's trusted list.

Because Python's operator module exposes primitives such as operator.attrgetter, operator.methodcaller, and operator.itemgetter, an attacker can chain these primitives to walk arbitrary attribute paths and call arbitrary callables. The result is a code reuse attack: every individual building block looks benign, but their composition reaches sensitive sinks such as os.system or subprocess.Popen.

Root Cause

The root cause is an inconsistency between the value that OperatorFuncNode reports during the audit phase and the value it resolves during construction. The audit checks the declared operator name, while execution resolves the underlying callable through a separate path that is never re-validated. This violates the trust boundary the library advertises to users who load partially trusted artifacts.

Attack Vector

Exploitation requires a victim to load a malicious skops file using skops.io.load or skops.io.loads, typically after reviewing the reported trusted types and approving them. The attack vector is local in the CVSS sense, but the file itself can be delivered through any channel that distributes ML models, including model hubs, shared storage, or email attachments.

text
# Patch excerpt from docs/changes.rst (skops v0.12.0)
# Source: https://github.com/skops-dev/skops/commit/0aeca055509dfb48c1506870aabdd9e247adf603

v0.12
-----
- `huggingface_hub` dependency is now optional. :pr:`462` by `Adrin Jalali`_.
- Objects' `__reduce__` is used when the output of it is of the form
  `(type, (constructor_args,)` where type is the same as the `type(obj)`.
  :pr:`467` by `Adrin Jalali`_.
- `MethodNode` and `OperatorNode` have a hardened audit now, removing certain security
  vulnerabilities. :pr:`482` by `Adrin Jalali`_.

The patch hardens both MethodNode and OperatorNode so that the audited identity matches the executed callable, closing the code reuse path. See the GitHub Security Advisory GHSA-m7f4-hrc6-fwg3 for full advisory details.

Detection Methods for CVE-2025-54412

Indicators of Compromise

  • Skops model files (.skops) loaded from untrusted sources or unverified model registries.
  • Python processes spawning shells, subprocess, or network clients shortly after calls to skops.io.load.
  • Trusted-type prompts during model loading that list only innocuous primitives yet originate from unknown publishers.
  • Outbound connections from ML inference workloads to unexpected hosts immediately after model deserialization.

Detection Strategies

  • Inventory Python environments and flag any installation of skops at version 0.11.0 or earlier using pip show skops or SBOM data.
  • Hunt for process lineage where python is the parent of sh, bash, cmd.exe, or powershell.exe during model loading workflows.
  • Inspect skops files statically for references to operator.attrgetter, operator.methodcaller, or chained operator nodes before approving trusted types.

Monitoring Recommendations

  • Monitor file integrity on directories that store ML model artifacts to detect unauthorized replacement.
  • Alert on Python interpreters making outbound network connections from data science or training hosts that normally remain isolated.
  • Log every skops.io.load invocation along with the source path and the set of trusted types approved by the caller.

How to Mitigate CVE-2025-54412

Immediate Actions Required

  • Upgrade skops to version 0.12.0 or later in all production, training, and developer environments.
  • Audit existing model repositories for files produced by untrusted publishers and quarantine them until they can be re-verified.
  • Restrict model loading workflows to run under least-privilege service accounts without write access to source code or secrets.
  • Educate data science teams that approving trusted types in skops does not guarantee safety on versions 0.11.0 and below.

Patch Information

The fix is included in skops v0.12.0 via the hardening of MethodNode and OperatorNode audits, landed in pull request #482. Upgrade with pip install --upgrade 'skops>=0.12.0' and rebuild any container images that pin earlier versions.

Workarounds

  • Refuse to load skops files originating from untrusted publishers until the upgrade is complete.
  • Execute model deserialization inside an isolated sandbox such as a container with no network egress and a read-only filesystem.
  • Pin skops to a known-good version in requirements.txt or pyproject.toml and enforce the floor with dependency scanning in CI.
bash
# Upgrade skops to a patched version and verify the installed version
pip install --upgrade 'skops>=0.12.0'
python -c "import skops; print(skops.__version__)"

# Optional: scan environments for vulnerable installs
pip list --format=freeze | grep -i '^skops==' | awk -F'==' '$2 < "0.12.0" {print "Vulnerable: " $0}'

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.