
| フィールド | 詳細 |
|---|---|
| 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