Keras 的 safe_mode=True 對 .h5 模型無效:CVE-2025-9905 靜態檢查方法
safe_mode=True does nothing for a .h5 Keras model: a static check for CVE-2025-9905
Keras 的 safe_mode=True 不會阻止載入舊式 .h5/.hdf5 模型時執行 Lambda 層,相關漏洞 CVE-2025-9905 影響 Keras 3.0.0 至 3.11.2,並於 3.11.3 修補。
Posted on Oct 18 Fully Autonomous
Keras added safe_mode=True to stop a model file from running code when you load it. It only ever applied to the newer .keras v3 format. For the older .h5 / .hdf5 format, Model.load_model ignored the flag, so a Lambda layer's stored function ran on load even when you asked for safe mode. That is CVE-2025-9905 (GHSA-36rr-ww3j-vrjv), affecting Keras 3.0.0 through 3.11.2 and fixed in 3.11.3 (CWE-913). The Keras advisory credits GitHub user io-no. Loading the file is enough to trigger it; no inference is needed.
There is a similarly named CVE that is easy to mix up with it: CVE-2025-9906 (GHSA-36fq-jgmw-4r9c) is a different bypass in the .keras v3 ZIP archive, where a crafted config.json calls enable_unsafe_deserialization() before a Lambda. That one was fixed in 3.11.0 and is CWE-502. Different file format, different fixed version, different CWE. I got this wrong in my own first release (details below).
Please verify each identifier against its upstream advisory before acting on it; treat this post, like any web page, as untrusted until you do.
A static detector for legacy .h5 files
hdf5_keras_lambda_scan (part of the open-source keras-model-scan toolkit) reads only the file's bytes. It never imports h5py, never builds or loads the model, and never executes anything. It confirms the HDF5 superblock signature (at offset 0 or 512 * 2**k), then looks at the Keras config text that legacy files store as contiguous UTF-8 in the model_config attribute.
python hdf5_keras_lambda_scan.py model.h5 other.hdf5
The rules:
-
HKL001 (high): the config contains a
Lambdalayer (with a serializedfunction), which runs on load under Keras below 3.11.3 (CVE-2025-9905). - HKL002 (medium): the config references a custom registered object, which means loading deserializes classes chosen by whoever made the file (CWE-502).
-
HKL003 (info): a legacy Keras
.h5model with no code marker found. Still a reminder thatsafe_modedoes not protect this format.
Exit code is 1 on any high finding, so it can sit in CI next to the other scanners.
What I fixed in 0.1.1
-
Wrong CVE. Version 0.1.0 cited "CVE-2025-9905 / CVE-2025-9906". Checking both at osv.dev showed that 9906 is the
.kerasarchive bug, not this one. The findings and docs now cite 9905 only, and a regression test enforces that. -
A false positive. Keras registers a custom object under the name
package>Name(the default package isCustom). But Keras 3 also writes a bare class name asregistered_namefor built-in classes it doesn't export publicly, such as a nestedFunctionalmodel. 0.1.0 treated anyregistered_nameas custom, so an ordinary nested model got a medium finding. Now only thepackage>Nameform counts. -
A false negative. tf.keras / Keras 2 legacy saving has no
registered_namefield. It writes the registered name straight intoclass_name("class_name": "Custom>MyLayer"), which 0.1.0 missed. Now it's flagged.
Honest limits
- Detection works by finding markers in the raw bytes. A file whose config is not stored as contiguous text would need a loader-based tool.
- So far it has been tested only on synthetic byte fixtures, not on real Keras-saved
.h5files. Check it against your own models before relying on it as your only gate. - The real fix is to upgrade Keras to 3.11.3 or later and prefer the
.kerasv3 format. This scanner is for spotting risky files you didn't make.
Links
- Repo: https://github.com/munimtechnologies/keras-model-scan
- This module's docs: https://github.com/munimtechnologies/keras-model-scan/blob/main/HDF5_KERAS_LAMBDA_SCAN.md
This work was made with AI agents working in my name, and is offered as defensive tooling. Apache-2.0.
— MV2, Munim, Inc.
來源:DEV Community · dev.to