
| フィールド | 詳細 |
|---|
| 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 公開日 | 2026年1月15日 |
| NVD 最終更新日 | 2026年1月23日 |
| 情報源 / CNA | Google Inc. |
| 報告者 | HyperPS (Sarvesh Patil)、huntr.dev / GHSA 経由 |
| 修正状況 | マージ済み — PR #21880 |
Google Keras バージョン 3.0.0 から 3.13.0 の全プラットフォームにおいて、HDF5 ウェイト読み込みコンポーネントにサービス拒否(DoS)の脆弱性が存在します。この脆弱性は、.keras アーカイブ内で宣言された HDF5 データセットのシェイプ(形状)メタデータを処理する際に、検証やスロットリングが一切行われないことに起因します。
HDF5 形式では、データセットが自身のシェイプ(テンソルの次元)をメタデータとして宣言できます。Keras が .keras アーカイブからモデルのウェイトを読み込む際、この宣言されたシェイプを読み取り、データが転送される前に、対応するメモリブロックの割り当てを試みます。Keras は割り当て前に宣言されたシェイプに対する境界チェックを行わないため、攻撃者は (1000000, 1000000, 1000000) のような天文学的に巨大なシェイプを宣言した model.weights.h5 ファイルを作成し、Keras にペタバイト規模のメモリ割り当てを試行させることができます。これにより、システムの全メモリが枯渇し、Python インタープリタがクラッシュします。
モデルの読み込み後、推論や追加の操作は必要ありません。攻撃は読み込み時に完全に発動します。
| ファイル | 説明 |
|---|---|
keras/src/saving/file_editor.py | KerasFileEditor._extract_weights_from_store() — HDF5 データセットのシェイプを読み取り、サイズ検証やスロットリングなしでメモリを割り当てます |
この脆弱性は、.keras アーカイブ内に埋め込まれた HDF5 ストアからモデルのウェイトテンソルをデシリアライズする役割を担う KerasFileEditor クラスに特に存在します。
| メトリクス | 値 | 意味 |
|---|---|---|
| 攻撃元区分 (AV) | ネットワーク | 配布されたモデルファイル経由でリモートから悪用可能 |
| 攻撃複雑性 (AC) | 低 | 特別な条件や競合状態は不要 |
| 攻撃要件 (AT) | なし | 前提となるデプロイ設定は不要 |
| 必要な権限 (PR) | なし | 認証やアカウントは不要 |
| ユーザー操作 (UI) | パッシブ | 被害者が悪意のある .keras アーカイブを読み込む必要がある |
| 脆弱なシステムの可用性 (VA) | 高 | Python インタープリタがクラッシュし、サービスが完全に利用不能になる |
| 脆弱なシステムの機密性 (VC) | なし | データの開示は発生しない |
| 脆弱なシステムの完全性 (VI) | なし | データの改変は発生しない |
| 後続システムへの影響 (SC/SI/SA) | なし | 影響は読み込みプロセスに限定される |
.keras モデルアーカイブを読み込む本番環境および研究用パイプラインはすべて脆弱です| 環境 | リスク |
|---|---|
ユーザーがアップロードした .keras ファイルを受け付ける公開モデル推論 API | 攻撃者が単一のリクエストで推論サービスをクラッシュさせる |
| コミュニティ製モデルのダウンロードをホストする ML プラットフォーム (例: Hugging Face) | 毒を仕込まれたモデルが、それをダウンロードして読み込むすべての研究者に対して DoS を引き起こす |
| 連合学習環境 | 悪意のある参加者が細工されたウェイトファイルを配布し、コーディネーターまたはピアノードをクラッシュさせる |
| モデルチェックポイントを読み込む CI/CD パイプライン | 侵害または差し替えられたチェックポイントがパイプラインの失敗と利用不能を引き起こす |
| 実行時にモデルをホットリロードするチャットボットや NLP サービス | 単一の悪意のあるリロードリクエストでサービスが停止する |
HDF5 ファイル形式は、シェイプ宣言を含むテンソルのメタデータを、実際のデータバイトとは別に格納します。KerasFileEditor._extract_weights_from_store() がデータセットエントリに遭遇すると、宣言されたシェイプを読み取り、ディスクからデータを読み込む前に、対応する次元の配列を事前割り当てするために NumPy を呼び出します。
シェイプはメタデータであるため、わずか数キロバイトの HDF5 ファイルでも、ペタバイト規模のメモリを必要とするシェイプを宣言できます。ファイルサイズに対する割り当てサイズの比率により、これは非常に効果的な増幅攻撃となります。
(1000000, 1000000, 1000000) のようなシェイプで 32 ビット浮動小数点の dtype を使用した場合、約 4,000 ペタバイト のメモリが要求されます。OS の OOM キラーまたは 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
np.zeros() を呼び出す前に shape に対するチェックが一切ないことが根本原因です。
この情報は教育および防御目的のみで提供されています。所有していないシステム、または明示的なテスト許可を得ていないシステムに対してテストを行わないでください。
.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 で終了するか、OS の OOM ハンドラによって強制終了されます。
観測可能な症状:
load_model() または load_weights() 中に Python インタープリタのクラッシュまたは MemoryError が発生するh5dump で検出可能な、極端に大きな宣言済みデータセットシェイプを持つ異常な HDF5 ファイルこの脆弱性は、研究者 (HyperPS / Sarvesh Patil) による PR #21880 で解決されました。2025年12月29日 に keras-team:master へマージされ、Keras メンテナーの hertschuh によってレビューおよび承認されました。
| リソース | リンク |
|---|---|
| 修正プルリクエスト | https://github.com/keras-team/keras/pull/21880 |
| マージコミット | 7360d4f |
| バックポート依頼 (3.12.x) | Issue #22031 |
このパッチは keras/src/saving/file_editor.py の KerasFileEditor._extract_weights_from_store() を変更し、メモリ割り当てが発生する前に以下の保護を追加します:
inner_path の処理を修正しますこの修正は、すべての有効な 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 の修正を含むバージョン(3.13.0 以降の master ビルド、または公式の修正済みリリース)に更新する |
| 信頼できないモデルファイルを読み込まない | 事前の整合性検証なしに、信頼できない、未検証の、またはコミュニティ由来の場所から .keras や .weights.h5 ファイルを決して読み込まない |
| ファイルの整合性を検証する | 読み込み前に、モデルアーカイブの SHA-256 チェックサムを公開元が提供するハッシュと照合する |
| h5dump による事前スキャン | Keras で読み込む前に、h5dump --header <file> を使用して HDF5 ファイル内のデータセットシェイプのメタデータを検査する |
| 最小権限 | cgroups や ulimit でメモリ制限を適用した制限付き OS ユーザーでモデル提供プロセスを実行し、被害範囲を限定する |
| コンテナ化 | メモリ制限付きのサンドボックス化されたコンテナでモデル読み込みを分離し、単一のクラッシュが他のサービスに影響を与えないようにする |
| メモリ監視 | モデル読み込み操作を計測し、異常なメモリ割り当てパターンを警告する |
pip によるアップグレード:
pip install --upgrade keras
インストール済みバージョンの確認:
python -c "import keras; print(keras.__version__)"
HDF5 ウェイトファイルの疑わしいシェイプの事前スキャン:
h5dump --header model.weights.h5 | grep -i "DATASPACE"
| 日付 | イベント |
|---|---|
| 2025年11月29日 | HyperPS により修正 PR #21880 が keras-team/keras に提出 |
| 2025年12月1日 | Keras メンテナーの hertschuh が参考文献を要求し、レビュー開始 |
| 2025年12月26日 | メンテナーレビュー完了。最終フィードバックに対応 |
| 2025年12月29日 | PR #21880 が承認され、keras-team:master にマージ |
| 2026年1月15日 | CVE-2026-0897 が NVD に公開 |
| 2026年1月19日 | Keras 3.12.x へのバックポート依頼が開始 (Issue #22031) |
| 2026年1月23日 | NVD レコードが最終更新 |
このリポジトリは、CVE-2026-0897 を 教育、研究、および防御的セキュリティ目的 に限定して文書化しています。概念実証コードと技術的詳細は、開発者、セキュリティエンジニア、およびシステム管理者がこの脆弱性を理解、評価、および修復するのを支援するために提供されています。
明示的な許可なくこの情報を使用してシステム、サービス、または個人に害を及ぼすことは、違法かつ非倫理的行為です。著者は、本書に含まれる情報の悪用に対して一切の責任を負いません。
貢献者 @mohitf070304