
Asignación de recursos sin límites ni limitación de velocidad en el componente de carga de pesos HDF5 en Google Keras 3.0.0 hasta 3.13.0 en todas las plataformas permite a un atacante remoto causar una Denegación de Servicio (DoS) mediante el agotamiento de la memoria y un bloqueo del intérprete de Python a través de un archivo .keras manipulado.
| Campo | Detalles |
|---|
| ID CVE | CVE-2026-0897 |
| Paquete | keras (Google Keras) |
| Registro | PyPI |
| Versiones Afectadas | 3.0.0 hasta 3.13.0 (inclusive) |
| Tipo de Vulnerabilidad | CWE-770: Asignación de Recursos sin Límites o Aceleración |
| Puntuación CVSS | 7.1 Alta (CVSS 4.0, CNA: Google Inc.) |
| Vector CVSS | CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N |
| Vector de Ataque | Red |
| Complejidad del Ataque | Baja |
| Privilegios Requeridos | Ninguno |
| Interacción del Usuario | Pasiva (la víctima carga un archivo de modelo) |
| Impacto en Disponibilidad | Alto |
| Impacto en Confidencialidad | Ninguno |
| Impacto en Integridad | Ninguno |
| Publicado en NVD | 15 de enero de 2026 |
| Última Modificación en NVD | 23 de enero de 2026 |
| Fuente / CNA | Google Inc. |
| Reportado Por | HyperPS (Sarvesh Patil) vía huntr.dev / GHSA |
| Estado de la Corrección | Fusionado — PR #21880 |
Existe una vulnerabilidad de Denegación de Servicio en el componente de carga de pesos HDF5 de Google Keras versiones 3.0.0 hasta 3.13.0 en todas las plataformas. La vulnerabilidad se debe a la ausencia de cualquier validación o limitación al procesar los metadatos de forma de conjuntos de datos HDF5 declarados dentro de un archivo .keras.
El formato HDF5 permite que los conjuntos de datos declaren su forma (dimensiones del tensor) como metadatos. Cuando Keras carga los pesos del modelo desde un archivo .keras, lee esta forma declarada e intenta asignar un bloque de memoria correspondiente antes de que se transfiera cualquier dato. Debido a que Keras no realiza ninguna verificación de límites sobre la forma declarada antes de la asignación, un atacante puede crear un archivo model.weights.h5 que declare una forma astronómicamente grande — por ejemplo (1000000, 1000000, 1000000) — lo que provoca que Keras intente una asignación de memoria a escala de petabytes. Esto agota toda la memoria disponible del sistema y bloquea el intérprete de Python.
No se requiere inferencia ni interacción adicional después de cargar el modelo. El ataque se activa completamente en el momento de la carga.
| Archivo | Descripción |
|---|---|
keras/src/saving/file_editor.py | KerasFileEditor._extract_weights_from_store() — lee la forma del conjunto de datos HDF5 y asigna memoria sin validación de tamaño ni limitación |
La vulnerabilidad se ubica específicamente en la clase KerasFileEditor, responsable de deserializar los tensores de pesos del modelo desde los almacenes HDF5 incrustados dentro de los archivos .keras.
| Métrica | Valor | Significado |
|---|---|---|
| Vector de Ataque (AV) | Red | Explotable remotamente mediante un archivo de modelo distribuido |
| Complejidad del Ataque (AC) | Baja | No se requieren condiciones especiales ni condiciones de carrera |
| Requisitos del Ataque (AT) | Ninguno | No se necesita configuración de despliegue previa |
| Privilegios Requeridos (PR) | Ninguno | No se requiere autenticación ni cuenta |
| Interacción del Usuario (UI) | Pasiva | La víctima debe cargar el archivo .keras malicioso |
| Disponibilidad del Sistema Vulnerable (VA) | Alta | El intérprete de Python se bloquea; el servicio queda completamente no disponible |
| Confidencialidad del Sistema Vulnerable (VC) | Ninguna | No hay divulgación de datos |
| Integridad del Sistema Vulnerable (VI) | Ninguna | No hay modificación de datos |
| Impacto en Sistemas Posteriores (SC/SI/SA) | Ninguno | El impacto se limita al proceso de carga |
.keras de fuentes no confiables o proporcionadas por el usuario es vulnerable| Contexto | Riesgo |
|---|---|
APIs públicas de servidores de modelos que aceptan archivos .keras subidos por el usuario | El atacante bloquea el servicio de inferencia con una sola solicitud |
| Plataformas de ML que alojan descargas de modelos de la comunidad (p. ej., Hugging Face) | Un modelo envenenado causa DoS a cualquier investigador que lo descargue y cargue |
| Entornos de aprendizaje federado | Un participante malicioso distribuye un archivo de pesos manipulado para bloquear el coordinador o los nodos pares |
| Pipelines de CI/CD que cargan checkpoints de modelos | Un checkpoint comprometido o sustituido causa fallo del pipeline e indisponibilidad |
| Servicios de chatbots o NLP que recargan modelos en caliente en tiempo de ejecución | Una sola solicitud de recarga maliciosa derriba el servicio |
El formato de archivo HDF5 almacena los metadatos de los tensores — incluidas las declaraciones de forma — por separado de los bytes de datos reales. Cuando KerasFileEditor._extract_weights_from_store() encuentra una entrada de conjunto de datos, lee la forma declarada y llama a NumPy para pre-asignar un array de las dimensiones correspondientes antes de leer cualquier dato del disco.
Debido a que la forma son metadatos, un archivo HDF5 mínimo puede declarar una forma que requeriría petabytes de memoria mientras el archivo en sí permanece con solo unos pocos kilobytes de tamaño. La proporción entre el tamaño del archivo y el tamaño de la asignación convierte esto en un ataque de amplificación altamente efectivo.
Una forma como (1000000, 1000000, 1000000) con un dtype de float de 32 bits solicitaría aproximadamente 4,000 petabytes de memoria. El killer de falta de memoria del SO o el asignador de Python bloquearán el proceso casi instantáneamente.
# keras/src/saving/file_editor.py (pre-fix, simplified)
def _extract_weights_from_store(self, h5_file, inner_path=""):
for key in h5_file.keys():
obj = h5_file[key]
if isinstance(obj, h5py.Dataset):
# Shape is read from metadata — no validation performed
shape = obj.shape
# NumPy attempts to allocate based on declared shape
data = np.zeros(shape, dtype=obj.dtype) # VULNERABLE: unbounded allocation
La ausencia de cualquier verificación sobre shape antes de llamar a np.zeros() es la causa raíz.
Esta información se proporciona únicamente con fines educativos y defensivos. No pruebe contra sistemas que no le pertenezcan o para los cuales no tenga autorización explícita de pruebas.
.keras Malicioso# generate_shape_bomb.py
import h5py
import zipfile
import json
import os
# Step 1: Create a minimal HDF5 weights file with a hostile shape declaration
with h5py.File("model.weights.h5", "w") as f:
grp = f.create_group("layers/dense/vars")
# Declare shape that would require petabytes of memory to allocate
# Actual data is never written — only the metadata shape declaration is malicious
grp.create_dataset(
"0",
shape=(0,), # actual stored data: empty
maxshape=(None,),
dtype="float32",
data=[]
)
# Override shape metadata to declare hostile dimensions
# (achieved via direct HDF5 attribute manipulation in a real attack)
# Step 2: Package into a valid .keras archive structure
config = {
"class_name": "Sequential",
"config": {"name": "sequential", "trainable": True, "layers": []},
"keras_version": "3.0.0",
"backend": "tensorflow"
}
with zipfile.ZipFile("malicious_model.keras", "w") as zf:
zf.writestr("config.json", json.dumps(config))
zf.writestr("model.weights.h5", open("model.weights.h5", "rb").read())
print("[+] Malicious .keras archive generated: malicious_model.keras")
# trigger.py
import keras
print("[+] Loading malicious model...")
# The crash occurs at load time — no inference required
model = keras.saving.load_model("malicious_model.keras")
print("[-] This line is never reached — interpreter has crashed")
Resultado esperado: El intérprete de Python termina con un MemoryError o es eliminado por el manejador de falta de memoria del SO antes de que la carga se complete.
Síntomas observables:
MemoryError durante load_model() o load_weights()h5dumpLa vulnerabilidad fue resuelta por el investigador (HyperPS / Sarvesh Patil) en el PR #21880, fusionado en keras-team:master el 29 de diciembre de 2025, revisado y aprobado por el mantenedor de Keras hertschuh.
| Recurso | Enlace |
|---|---|
| Pull Request de la Corrección | https://github.com/keras-team/keras/pull/21880 |
| Commit de Fusión | 7360d4f |
| Solicitud de Backport (3.12.x) | Issue #22031 |
El parche modifica KerasFileEditor._extract_weights_from_store() en keras/src/saving/file_editor.py para añadir las siguientes protecciones antes de que ocurra cualquier asignación de memoria:
inner_path durante el recorrido recursivo del almacén HDF5La corrección es compatible con versiones anteriores para todos los archivos de pesos válidos de Keras.
# keras/src/saving/file_editor.py (post-fix logic, simplified)
MAX_BYTES = 1 * 1024 ** 3 # 1 GiB hard cap per dataset
MAX_RANK = 64
def _validate_hdf5_dataset_shape(shape, dtype):
"""Reject hostile HDF5 shape declarations before any allocation."""
if len(shape) > MAX_RANK:
raise ValueError(
f"HDF5 dataset has rank {len(shape)}, which exceeds the "
f"maximum permitted rank of {MAX_RANK}. This may indicate "
"a malicious file."
)
for dim in shape:
if dim < 0:
raise ValueError(
f"HDF5 dataset contains a negative dimension ({dim}). "
"This may indicate a malicious file."
)
import math, numpy as np
try:
total_elements = math.prod(shape)
except OverflowError:
raise ValueError(
"HDF5 dataset shape overflows integer arithmetic. "
"This may indicate a malicious file."
)
itemsize = np.dtype(dtype).itemsize
total_bytes = total_elements * itemsize
if total_bytes > MAX_BYTES:
raise ValueError(
f"HDF5 dataset would require {total_bytes / 1024**3:.2f} GiB to "
f"load, which exceeds the 1 GiB safety limit. This may indicate "
"a malicious file."
)
| Acción | Detalles |
|---|---|
| Actualizar Keras | Actualice a una versión que incluya la corrección del PR #21880 (builds de master posteriores a 3.13.0 o cualquier versión oficial parcheada) |
| No Cargar Archivos de Modelo No Confiables | Nunca cargue archivos .keras o .weights.h5 de fuentes no confiables, no verificadas o provenientes de la comunidad sin verificación previa de integridad |
| Verificar la Integridad de los Archivos | Valide las sumas de verificación SHA-256 de los archivos de modelo contra los hashes proporcionados por el publicador antes de cargarlos |
| Pre-examen con h5dump | Use h5dump --header <archivo> para inspeccionar los metadatos de forma de los conjuntos de datos en archivos HDF5 antes de cargarlos en Keras |
| Privilegio Mínimo | Ejecute los procesos de servidores de modelos bajo un usuario restringido del SO con límites de memoria aplicados mediante cgroups o ulimit para acotar el radio de impacto |
| Contenedorización | Aísle la carga de modelos en un contenedor sandbox con límites de memoria para evitar que un solo bloqueo afecte a otros servicios |
| Monitorización de Memoria | Instrumente las operaciones de carga de modelos para alertar sobre patrones anormales de asignación de memoria |
Actualización vía pip:
pip install --upgrade keras
Verificar la versión instalada:
python -c "import keras; print(keras.__version__)"
Pre-examinar un archivo de pesos HDF5 para detectar formas sospechosas:
h5dump --header model.weights.h5 | grep -i "DATASPACE"
| Fecha | Evento |
|---|---|
| 29 de noviembre de 2025 | El PR de corrección #21880 se envía a keras-team/keras por HyperPS |
| 1 de diciembre de 2025 | El mantenedor de Keras hertschuh solicita referencias; comienza la revisión |
| 26 de diciembre de 2025 | Revisión del mantenedor completada; se abordan los comentarios finales |
| 29 de diciembre de 2025 | PR #21880 aprobado y fusionado en keras-team:master |
| 15 de enero de 2026 | CVE-2026-0897 publicado en NVD |
| 19 de enero de 2026 | Se abre la solicitud de backport para Keras 3.12.x (Issue #22031) |
| 23 de enero de 2026 | Registro NVD modificado por última vez |
| Recurso | Enlace |
|---|---|
| Entrada NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-0897 |
| Registro CVE Oficial | https://cve.org/CVERecord?id=CVE-2026-0897 |
| Aviso de GitHub (GHSA) | https://github.com/advisories/GHSA-xfhx-r7ww-5995 |
| Pull Request de la Corrección | https://github.com/keras-team/keras/pull/21880 |
| Commit de Fusión | https://github.com/keras-team/keras/commit/7360d4f0d764fbb1fa9c6408fe53da41974dd4f6 |
| Solicitud de Backport | https://github.com/keras-team/keras/issues/22031 |
| Keras en PyPI | https://pypi.org/project/keras/ |
| CWE-770 | https://cwe.mitre.org/data/definitions/770.html |
| Documentación del Formato HDF5 | https://www.hdfgroup.org/solutions/hdf5/ |
Este repositorio documenta CVE-2026-0897 estrictamente con fines educativos, de investigación y de seguridad defensiva. El código de prueba de concepto y los detalles técnicos se proporcionan para ayudar a desarrolladores, ingenieros de seguridad y administradores de sistemas a comprender, evaluar y remediar esta vulnerabilidad.
Cualquier uso de esta información para causar daño a sistemas, servicios o individuos sin autorización explícita es ilegal y poco ético. El autor no asume ninguna responsabilidad por el uso indebido de la información contenida aquí.
Colaboradores @mohitf070304