
Allocation de ressources sans limites ni limitation de débit dans le composant de chargement des poids HDF5 de Google Keras 3.0.0 à 3.13.0 sur toutes les plateformes permet à un attaquant distant de provoquer un déni de service (DoS) via l'épuisement de la mémoire et un crash de l'interpréteur Python à l'aide d'un fichier .keras contrefait.
| Champ | Détails |
|---|---|
| Identifiant CVE | CVE-2026-0897 |
| Paquet | keras (Google Keras) |
| Registre | PyPI |
| Versions affectées | 3.0.0 à 3.13.0 (inclus) |
| Type de vulnérabilité | CWE-770 : Allocation de ressources sans limites ni régulation |
| Score CVSS | 7.1 Élevé (CVSS 4.0, CNA : Google Inc.) |
| Vecteur 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 |
| Vecteur d'attaque | Réseau |
| Complexité d'attaque | Faible |
| Privilèges requis | Aucun |
| Interaction utilisateur | Passive (la victime charge un fichier de modèle) |
| Impact sur la disponibilité | Élevé |
| Impact sur la confidentialité | Aucun |
| Impact sur l'intégrité | Aucun |
| Publiée sur NVD | 15 janvier 2026 |
| Dernière modification NVD | 23 janvier 2026 |
| Source / CNA | Google Inc. |
| Signalée par | HyperPS (Sarvesh Patil) via huntr.dev / GHSA |
| État du correctif | Fusionné — PR #21880 |
Une vulnérabilité de déni de service existe dans le composant de chargement de poids HDF5 de Google Keras versions 3.0.0 à 3.13.0 sur toutes les plateformes. La vulnérabilité est causée par l'absence de validation ou de limitation lors du traitement des métadonnées de forme de jeu de données HDF5 déclarées dans une archive .keras.
Le format HDF5 permet aux jeux de données de déclarer leur forme (dimensions du tenseur) sous forme de métadonnées. Lorsque Keras charge des poids depuis une archive .keras, il lit cette forme déclarée et tente d'allouer un bloc mémoire correspondant avant tout transfert de données. Comme Keras n'effectue aucun contrôle des limites sur la forme déclarée avant l'allocation, un attaquant peut créer un fichier model.weights.h5 déclarant une forme astronomiquement grande — par exemple (1000000, 1000000, 1000000) — ce qui amène Keras à tenter une allocation mémoire à l'échelle du pétaoctet. Cela épuise toute la mémoire système disponible et fait planter l'interpréteur Python.
Aucune inférence ou interaction supplémentaire n'est requise après le chargement du modèle. L'attaque est entièrement déclenchée au moment du chargement.
| Fichier | Description |
|---|---|
keras/src/saving/file_editor.py | KerasFileEditor._extract_weights_from_store() — lit la forme du jeu de données HDF5 et alloue la mémoire sans validation de taille ni limitation |
La vulnérabilité se situe précisément dans la classe KerasFileEditor, chargée de désérialiser les tenseurs de poids du modèle depuis les magasins HDF5 intégrés dans les archives .keras.
| Métrique | Valeur | Signification |
|---|---|---|
| Vecteur d'attaque (AV) | Réseau | Exploitable à distance via un fichier de modèle distribué |
| Complexité d'attaque (AC) | Faible | Aucune condition particulière ni course requise |
| Exigences d'attaque (AT) | Aucune | Aucune configuration de déploiement préalable requise |
| Privilèges requis (PR) | Aucun | Aucune authentification ni compte requis |
| Interaction utilisateur (UI) | Passive | La victime doit charger l'archive .keras malveillante |
| Disponibilité du système vulnérable (VA) | Élevée | L'interpréteur Python plante ; le service devient totalement indisponible |
| Confidentialité du système vulnérable (VC) | Aucune | Aucune divulgation de données |
| Intégrité du système vulnérable (VI) | Aucune | Aucune modification de données |
| Impact sur les systèmes suivants (SC/SI/SA) | Aucun | L'impact est limité au processus de chargement |
.keras provenant de sources non fiables ou fournies par l'utilisateur est vulnérable| Contexte | Risque |
|---|---|
API publiques de service de modèles qui acceptent des fichiers .keras téléversés par les utilisateurs | L'attaquant fait planter le service d'inférence avec une seule requête |
| Plateformes ML hébergeant des téléchargements de modèles communautaires (par ex. Hugging Face) | Un modèle empoisonné provoque un DoS pour tout chercheur qui le télécharge et le charge |
| Environnements d'apprentissage fédéré | Un participant malveillant distribue un fichier de poids conçu pour faire planter le coordinateur ou les nœuds pairs |
| Pipelines CI/CD qui chargent des points de contrôle de modèles | Un point de contrôle compromis ou substitué provoque une défaillance du pipeline et son indisponibilité |
| Chatbots ou services NLP qui rechargent les modèles à chaud au moment de l'exécution | Une seule requête de rechargement malveillante met le service hors service |
Le format de fichier HDF5 stocke les métadonnées des tenseurs — y compris les déclarations de forme — séparément des octets de données réels. Lorsque KerasFileEditor._extract_weights_from_store() rencontre une entrée de jeu de données, il lit la forme déclarée et appelle NumPy pour pré-allouer un tableau des dimensions correspondantes avant de lire toute donnée depuis le disque.
Comme la forme est une métadonnée, un fichier HDF5 minimal peut déclarer une forme qui nécessiterait des pétaoctets de mémoire alors que le fichier lui-même ne pèse que quelques kilo-octets. Le rapport entre la taille du fichier et la taille de l'allocation fait de cette attaque une attaque par amplification très efficace.
Une forme telle que (1000000, 1000000, 1000000) avec un dtype flottant 32 bits demanderait environ 4 000 pétaoctets de mémoire. Le « out-of-memory killer » du système d'exploitation ou l'allocateur Python fera planter le processus presque instantanément.
# 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
L'absence de toute vérification de shape avant l'appel à np.zeros() est la cause racine.
Ces informations sont fournies à des fins éducatives et défensives uniquement. Ne testez pas sur des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas d'autorisation explicite.
.keras malveillante