Skip to main content
CVE Vulnerability Database

CVE-2025-9906: Keras Model.load_model RCE Vulnerability

CVE-2025-9906 is a remote code execution vulnerability in Keras that exploits Model.load_model to execute arbitrary code even with safe_mode enabled. This article covers technical details, affected versions, and mitigations.

Published:

CVE-2025-9906 Overview

CVE-2025-9906 is an insecure deserialization vulnerability [CWE-502] in the Keras Model.load_model method. Attackers can achieve arbitrary code execution by crafting a malicious .keras model archive, even when safe_mode=True is set. The exploit bypasses safe mode by embedding a config.json that calls keras.config.enable_unsafe_deserialization(), then leverages the Lambda layer to execute pickled Python code. The vulnerability affects the Keras machine learning framework and poses substantial risk to any pipeline that loads third-party model files.

Critical Impact

A user who loads an untrusted .keras file executes attacker-controlled Python code within the host process, compromising confidentiality, integrity, and availability of the ML environment.

Affected Products

  • Keras (keras:keras) - all versions prior to the patched release
  • Machine learning pipelines that call Model.load_model on untrusted .keras archives
  • Downstream frameworks and applications that bundle vulnerable Keras versions

Discovery Timeline

  • 2025-09-19 - CVE-2025-9906 published to NVD
  • 2026-06-17 - Last updated in NVD database

Technical Details for CVE-2025-9906

Vulnerability Analysis

The .keras archive is a ZIP-like container holding model metadata, weights, and a config.json describing the model graph. Keras processes archive entries sequentially during Model.load_model. The safe deserialization mode is intended to block execution of arbitrary Python inside Lambda layers, which store code as pickled objects.

The flaw stems from the loader honoring configuration directives before enforcing the safe-mode invariant across the full archive. An attacker places keras.config.enable_unsafe_deserialization() as the first processed element, which flips the internal safe-mode flag at runtime. A subsequent Lambda layer entry then deserializes attacker-supplied pickled code, which executes with the privileges of the loading process.

This is a classic deserialization-to-code-execution chain [CWE-502]. The attack succeeds against defenders who explicitly set safe_mode=True under the assumption that the flag is authoritative.

Root Cause

Safe mode is treated as mutable process state rather than an immutable per-load contract. Because enable_unsafe_deserialization() can be invoked from within the archive being loaded, the security boundary collapses. The Lambda layer implementation continues to rely on pickle for callable serialization, which is inherently unsafe when the source is untrusted.

Attack Vector

Exploitation requires a victim to load an attacker-supplied .keras file via Model.load_model. Distribution channels include public model hubs, shared notebooks, supply-chain compromise of internal model registries, and phishing attachments. No network access to the target is required; the attack executes locally in the Python interpreter that invokes the loader. See the Keras Pull Request #21429 for the upstream fix discussion.

No public proof-of-concept exploit code is referenced in the advisory. The vulnerability mechanism is described in prose above rather than reproduced here.

Detection Methods for CVE-2025-9906

Indicators of Compromise

  • Presence of enable_unsafe_deserialization string within config.json inside .keras archives
  • Lambda layer entries in model configuration that contain base64-encoded or pickled Python callables
  • Unexpected child processes spawned from Python interpreters running ML training or inference workloads
  • Outbound network connections initiated immediately after a Model.load_model call

Detection Strategies

  • Statically scan .keras archives before loading, unzipping the container and inspecting config.json for enable_unsafe_deserialization and Lambda class references
  • Monitor Python process telemetry for pickle.loads or marshal.loads calls originating from Keras loader stack frames
  • Alert on ML worker processes that execute shell utilities, modify ~/.ssh, or write to persistence locations after loading a model

Monitoring Recommendations

  • Enable command-line and process-lineage logging on hosts running Keras workloads and ship events to a central data lake
  • Track SHA-256 hashes of model files ingested into training and inference pipelines and correlate against known-good baselines
  • Instrument model registries to log the uploader identity, source URL, and file hash for every .keras artifact

How to Mitigate CVE-2025-9906

Immediate Actions Required

  • Upgrade Keras to the fixed release that incorporates Pull Request #21429
  • Audit existing model registries and remove .keras files whose provenance cannot be verified
  • Restrict Model.load_model calls to models originating from trusted, signed sources
  • Run model-loading workloads under least-privilege service accounts with no write access to shared storage or secrets

Patch Information

The upstream fix is tracked in the Keras repository at keras-team/keras Pull Request #21429. Apply the vendor patch by upgrading through your Python package manager and rebuilding any container images that pin the vulnerable Keras version.

Workarounds

  • Do not load .keras archives received from untrusted sources, regardless of the safe_mode setting
  • Execute model loading inside sandboxed environments such as gVisor, Firecracker, or ephemeral containers with no network egress
  • Prefer weights-only formats and reconstruct model architecture from trusted, code-reviewed definitions
  • Enforce SHA-256 allowlists at the model registry so only vetted archives can be pulled by training or inference jobs
bash
# Upgrade Keras to a patched release
pip install --upgrade keras

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

# Inspect a .keras archive before loading (manual triage)
unzip -p suspicious_model.keras config.json | grep -E "enable_unsafe_deserialization|Lambda"

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.