CVE ID: CVE-2026-0897
Product: Google Keras
Vulnerability Type: Memory Exhaustion / Denial of Service (DoS)
Severity: High
CVSS Score: 7.1 (High)
Attack Vector: Network (via untrusted model files)
Exploitability: Low complexity, no privileges required
Exploit Availability: No mature public exploit; proof-of-concept possible for educational/research purposes
Impact: Service crash, container restart loops, application unavailability
What this vulnerability is
This vulnerability exists in how Keras loads model weight files stored in HDF5 (.h5) format inside a .keras model archive.
When Keras loads a model, it reads metadata from the HDF5 file that describes tensor shapes and sizes. In vulnerable versions, Keras trusts this metadata blindly.
An attacker can craft a malicious .keras file where the HDF5 dataset claims to have extremely large tensor dimensions (for example, trillions of elements).
Keras then attempts to allocate memory based on those declared dimensions.
The result:
- The Python process attempts to allocate massive memory
- System RAM is exhausted
- The process crashes or is killed by the OS (OOM killer)
- The application becomes unavailable
There is no code execution, but the service can be taken down reliably.
Affected Versions
- Keras versions:
3.0.0up to3.13.0 - Any application that loads
.kerasmodels from untrusted or semi-trusted sources is at risk
How an attacker could realistically exploit this
- The attacker creates a
.kerasfile containing a manipulatedmodel.weights.h5 - Inside the HDF5 file, dataset headers declare huge tensor shapes
- The attacker convinces a user, service, or pipeline to load the model:
- Model zoo
- CI/CD pipeline
- Automated ML workflow
- User-uploaded model feature
- Keras tries to load the weights
- Memory allocation explodes
- Application crashes → Denial of Service
This is especially dangerous in:
- Model marketplaces
- ML platforms
- APIs that auto-load uploaded models
- Kubernetes environments (causes CrashLoopBackOff)
Why this happens
- HDF5 allows datasets to describe shapes independently of actual stored data
- Keras did not enforce upper bounds on:
- Tensor dimensions
- Total allocation size
- NumPy attempts to allocate memory based on metadata alone
This is a classic case of unbounded resource allocation.
MITRE Mapping
- CWE-770 – Allocation of Resources Without Limits or Throttling
- Impact Category: Availability
- Threat Class: Application-level Denial of Service
Is there a PoC or exploit? (educational)
- There is no widely weaponized exploit published
- However, creating a PoC is trivial for anyone familiar with
h5py - A PoC involves crafting an HDF5 dataset with absurd dimensions (shape bomb)
- This is considered educational / research-level exploitation
The exploit requires the victim to load the malicious model. There is no drive-by or remote code execution.
How to detect exploitation or attempted abuse
Behavioral indicators
- Sudden memory spikes when loading a model
- Python process killed unexpectedly
- Kernel OOM messages
- Repeated container restarts
- Model load failures without clear validation errors
Key log sources
- Application logs (Python stack traces)
- Container runtime logs (Docker / Kubernetes)
- Host OS logs (
dmesg, syslog) - ML pipeline execution logs
Splunk Detection Rules
Rule 1 – Memory exhaustion during Keras model load
index=application_logs
(message="keras.models.load_model" OR message="KerasFileEditor" OR message="h5py")
| transaction maxspan=2m
| search message="MemoryError" OR message="Out of memory" OR message="Killed process"
| table _time host process message file_path
Rule 2 – Kubernetes container OOM after model load
index=kubernetes_logs
(message="OOMKilled" OR message="Killed container")
| search previous_message="load_model" OR previous_message="model.weights.h5"
| table _time namespace pod container message
Rule 3 – Abnormal memory spike (metrics-based)
index=metrics
metric_name=process_resident_memory_bytes
| delta value as mem_spike
| where mem_spike > 1073741824
| table _time host process mem_spike
Pre-Load Python Scanner
Use this before calling keras.models.load_model().
This scanner inspects HDF5 metadata only and never allocates tensors.
import h5py
import numpy as np
MAX_BYTES = 1 * 1024**3 # 1 GiB safety limit
MAX_DIMS = 8 # reasonable upper bound
def is_safe_hdf5_weights(h5_path):
with h5py.File(h5_path, "r") as f:
def check_dataset(name, obj):
if isinstance(obj, h5py.Dataset):
if len(obj.shape) > MAX_DIMS:
raise ValueError(f"Too many dimensions: {obj.shape}")
size = np.dtype(obj.dtype).itemsize
for dim in obj.shape:
size *= int(dim)
if size > MAX_BYTES:
raise ValueError(
f"Dataset '{name}' would allocate {size} bytes"
)
f.visititems(check_dataset)
return True
# Example usage
try:
is_safe_hdf5_weights("model.weights.h5")
print("Model appears safe to load")
except Exception as e:
print(f"Blocked unsafe model: {e}")
Best practice:
Reject the model immediately if this check fails.
Recommended Mitigations
- Upgrade Keras immediately
Apply the official upstream fix. Official patch / fix link:
👉 https://github.com/keras-team/keras/pull/21880 - Never auto-load untrusted models
Treat model files like executable content. - Add metadata validation
Use the pre-load scanner above. - Sandbox model loading
- Load models in isolated workers
- Apply memory limits (cgroups / Kubernetes limits)
- Monitor aggressively
- Alert on memory spikes
- Alert on repeated model load failures
- Set size expectations
- Define maximum allowed tensor sizes
- Enforce organizational standards for model artifacts
Why this vulnerability matters
Machine learning pipelines often assume models are “just data.”
This vulnerability proves they can be attack vectors.
Even without code execution, a single malicious model can:
- Take down production services
- Break CI/CD pipelines
- Cause cascading failures in distributed ML systems
Any environment that loads third-party or user-supplied models should treat this as high risk.
