chore(deps): update dependency keras to v3.13.1 [security] #147
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
==3.9.0→==3.13.1GitHub Vulnerability Alerts
CVE-2025-8747
Summary
It is possible to bypass the mitigation introduced in response to CVE-2025-1550, when an untrusted Keras v3 model is loaded, even when “safe_mode” is enabled, by crafting malicious arguments to built-in Keras modules.
The vulnerability is exploitable on the default configuration and does not depend on user input (just requires an untrusted model to be loaded).
Impact
Details
Keras’ safe_mode flag is designed to disallow unsafe lambda deserialization - specifically by rejecting any arbitrary embedded Python code, marked by the “lambda” class name.
https://github.com/keras-team/keras/blob/v3.8.0/keras/src/saving/serialization_lib.py#L641 -
A fix to the vulnerability, allowing deserialization of the object only from internal Keras modules, was introduced in the commit bb340d6780fdd6e115f2f4f78d8dbe374971c930.
However, it is still possible to exploit model loading, for example by reusing the internal Keras function
keras.utils.get_file, and download remote files to an attacker-controlled location.This allows for arbitrary file overwrite which in many cases could also lead to remote code execution. For example, an attacker would be able to download a malicious
authorized_keysfile into the user’s SSH folder, giving the attacker full SSH access to the victim’s machine.Since the model does not contain arbitrary Python code, this scenario will not be blocked by “safe_mode”. It will bypass the latest fix since it uses a function from one of the approved modules (
keras).Example
The following truncated
config.jsonwill cause a remote file download from https://raw.githubusercontent.com/andr3colonel/when_you_watch_computer/refs/heads/master/index.js to the local/tmpfolder, by sending arbitrary arguments to Keras’ builtin functionkeras.utils.get_file()-PoC
Download malicious_model_download.keras to a local directory
Load the model -
index.jswas created in the/tmpdirectoryFix suggestions
block_all_lambdathat allows users to completely disallow loading models with a Lambda layer.keras,keras_hub,keras_cv,keras_nlpmodules and remove/block all “gadget functions” which could be used by malicious ML models.lambda_whitelist_functionsthat allows users to specify a list of functions that are allowed to be invoked by a Lambda layerCredit
The vulnerability was discovered by Andrey Polkovnichenko of the JFrog Vulnerability Research
CVE-2025-9906
Arbitrary Code Execution in Keras
Keras versions prior to 3.11.0 allow for arbitrary code execution when loading a crafted
.kerasmodel archive, even whensafe_mode=True.The issue arises because the archive’s
config.jsonis parsed before layer deserialization. This can invokekeras.config.enable_unsafe_deserialization(), effectively disabling safe mode from within the loading process itself. An attacker can place this call first in the archive and then include aLambdalayer whose function is deserialized from a pickle, leading to the execution of attacker-controlled Python code as soon as a victim loads the model file.Exploitation requires a user to open an untrusted model; no additional privileges are needed. The fix in version 3.11.0 enforces safe-mode semantics before reading any user-controlled configuration and prevents the toggling of unsafe deserialization via the config file.
Affected versions: < 3.11.0
Patched version: 3.11.0
It is recommended to upgrade to version 3.11.0 or later and to avoid opening untrusted model files.
CVE-2025-9905
Note: This report has already been discussed with the Google OSS VRP team, who recommended that I reach out directly to the Keras team. I’ve chosen to do so privately rather than opening a public issue, due to the potential security implications. I also attempted to use the email address listed in your
SECURITY.md, but received no response.Summary
When a model in the
.h5(or.hdf5) format is loaded using the KerasModel.load_modelmethod, thesafe_mode=Truesetting is silently ignored without any warning or error. This allows an attacker to execute arbitrary code on the victim’s machine with the same privileges as the Keras application. This report is specific to the.h5/.hdf5file format. The attack works regardless of the other parameters passed toload_modeland does not require any sophisticated technique—.h5and.hdf5files are simply not checked for unsafe code execution.From this point on, I will refer only to the
.h5file format, though everything equally applies to.hdf5.Details
Intended behaviour
According to the official Keras documentation,
safe_modeis defined as:I understand that the behavior described in this report is somehow intentional, as
safe_modeis only applicable to.kerasmodels.However, in practice, this behavior is misleading for users who are unaware of the internal Keras implementation.
.h5files can still be loaded seamlessly usingload_modelwithsafe_mode=True, and the absence of any warning or error creates a false sense of security. Whether intended or not, I believe silently ignoring a security-related parameter is not the best possible design decision. At a minimum, ifsafe_modecannot be applied to a given file format, an explicit error should be raised to alert the user.This issue is particularly critical given the widespread use of the
.h5format, despite the introduction of newer formats.As a small anecdotal test, I asked several of my colleagues what they would expect when loading a
.h5file withsafe_mode=True. None of them expected the setting to be silently ignored, even after reading the documentation. While this is a small sample, all of these colleagues are cybersecurity researchers—experts in binary or ML security—and regular participants in DEF CON finals. I was careful not to give any hints about the vulnerability in our discussion.Technical Details
Examining the implementation of
load_modelinkeras/src/saving/saving_api.py, we can see that thesafe_modeparameter is completely ignored when loading.h5files. Here's the relevant snippet:As shown, when the file format is
.h5or.hdf5, the method delegates tolegacy_h5_format.load_model_from_hdf5, which does not use or check thesafe_modeparameter at all.Solution
Since the release of the new
.kerasformat, I believe the simplest and most effective way to address this misleading behavior—and to improve security in Keras—is to have thesafe_modeparameter raise an explicit error whensafe_mode=Trueis used with.h5/.hdf5files. This error should be clear and informative, explaining that the legacy format does not supportsafe_modeand outlining the associated risks of loading such files.I recognize this fix may have minor backward compatibility considerations.
If you confirm that you're open to this approach, I’d be happy to open a PR that includes the missing check.
PoC
From the attacker’s perspective, creating a malicious
.h5model is as simple as the following:From the victim’s side, triggering code execution is just as simple:
That’s all. The exploit occurs during model loading, with no further interaction required. The parameters passed to the method do not mitigate of influence the attack in any way.
As expected, the attacker can substitute the
exec(...)call with any payload. Whatever command is used will execute with the same permissions as the Keras application.Attack scenario
The attacker may distribute a malicious
.h5/.hdf5model on platforms such as Hugging Face, or act as a malicious node in a federated learning environment. The victim only needs to load the model—even withsafe_mode=Truethat would give the illusion of security. No inference or further action is required, making the threat particularly stealthy and dangerous.Once the model is loaded, the attacker gains the ability to execute arbitrary code on the victim’s machine with the same privileges as the Keras process. The provided proof-of-concept demonstrates a simple shell spawn, but any payload could be delivered this way.
CVE-2025-12058
The Keras.Model.load_model method, including when executed with the intended security mitigation safe_mode=True, is vulnerable to arbitrary local file loading and Server-Side Request Forgery (SSRF).
This vulnerability stems from the way the StringLookup layer is handled during model loading from a specially crafted .keras archive. The constructor for the StringLookup layer accepts a vocabulary argument that can specify a local file path or a remote file path.
Arbitrary Local File Read: An attacker can create a malicious .keras file that embeds a local path in the StringLookup layer's configuration. When the model is loaded, Keras will attempt to read the content of the specified local file and incorporate it into the model state (e.g., retrievable via get_vocabulary()), allowing an attacker to read arbitrary local files on the hosting system.
Server-Side Request Forgery (SSRF): Keras utilizes tf.io.gfile for file operations. Since tf.io.gfile supports remote filesystem handlers (such as GCS and HDFS) and HTTP/HTTPS protocols, the same mechanism can be leveraged to fetch content from arbitrary network endpoints on the server's behalf, resulting in an SSRF condition.
The security issue is that the feature allowing external path loading was not properly restricted by the safe_mode=True flag, which was intended to prevent such unintended data access.
CVE-2025-12060
Summary
Keras's
keras.utils.get_file()function is vulnerable to directory traversal attacks despite implementingfilter_safe_paths(). The vulnerability exists becauseextract_archive()uses Python'starfile.extractall()method without the security-criticalfilter="data"parameter. A PATH_MAX symlink resolution bug occurs before path filtering, allowing malicious tar archives to bypass security checks and write files outside the intended extraction directory.Details
Root Cause Analysis
Current Keras Implementation
The Critical Flaw
While Keras attempts to filter unsafe paths using
filter_safe_paths(), this filtering happens after the tar archive members are parsed and before actual extraction. However, the PATH_MAX symlink resolution bug occurs during extraction, not during member enumeration.Exploitation Flow:
filter_safe_paths()sees symlink paths that appear safeextractall()processes the filtered membersTechnical Details
The vulnerability exploits a known issue in Python's
tarfilemodule where excessively long symlink paths can cause resolution failures, leading to the symlink being treated as a literal path. This bypasses Keras's path filtering because:filter_safe_paths()operates on the parsed tar member informationextractall()../../../../etc/passwdto be writtenAffected Code Location
File:
keras/src/utils/file_utils.pyFunction:
extract_archive()around line 121Issue: Missing
filter="data"parameter intarfile.extractall()Proof of Concept
Environment Setup
Exploitation Steps
keras.utils.get_file()withextract=TrueKey Exploit Components
../../../target/file)Demonstration Results
Vulnerable behavior:
cache_dir/datasets/locationExpected secure behavior:
Impact
Vulnerability Classification
Who Is Impacted
Direct Impact:
keras.utils.get_file()withextract=TrueAttack Scenarios:
Affected Environments:
Risk Assessment
High Risk Factors:
Potential Consequences:
Recommended Fix
Immediate Mitigation
Replace the vulnerable extraction code with:
Long-term Solution
filter="data"parameter to alltarfile.extractall()callsBackward Compatibility
The fix maintains full backward compatibility as
filter="data"is the recommended secure default for Python 3.12+.References
Note: Reported in Huntr as well, but didn't get response
https://huntr.com/bounties/f94f5beb-54d8-4e6a-8bac-86d9aee103f4
CVE-2026-0897
Allocation of Resources Without Limits or Throttling in the HDF5 weight loading component in Google Keras 3.0.0 through 3.13.0 on all platforms allows a remote attacker to cause a Denial of Service (DoS) through memory exhaustion and a crash of the Python interpreter via a crafted .keras archive containing a valid model.weights.h5 file whose dataset declares an extremely large shape.
Release Notes
keras-team/keras (keras)
v3.13.1Compare Source
Bug Fixes & Improvements
import keraswhen using NumPy 2.0 or higher. (#21949)Full Changelog: keras-team/keras@v3.13.0...v3.13.1
v3.13.0Compare Source
BREAKING changes
Starting with version 3.13.0, Keras now requires
Python 3.11or higher. Please ensure your environment is updated to Python 3.11+ to install the latest version.Highlights
LiteRT Export
You can now export Keras models directly to the LiteRT format (formerly TensorFlow Lite) for on-device inference.
This changes comes with improvements to input signature handling and export utility documentation. The changes ensure that LiteRT export is only available when TensorFlow is installed, update the export API and documentation, and enhance input signature inference for various model types.
Example:
GPTQ Quantization
Introduced
keras.quantizers.QuantizationConfigAPI that allows for customizable weight and activation quantizers, providing greater flexibility in defining quantization schemes.Introduced a new
filtersargument to theModel.quantizemethod, allowing users to specify which layers should be quantized using regex strings, lists of regex strings, or a callable function. This provides fine-grained control over the quantization process.Refactored the GPTQ quantization process to remove heuristic-based model structure detection. Instead, the model's quantization structure can now be explicitly provided via
GPTQConfigor by overriding a newModel.get_quantization_layer_structuremethod, enhancing flexibility and robustness for diverse model architectures.Core layers such as
Dense,EinsumDense,Embedding, andReversibleEmbeddinghave been updated to accept and utilize the newQuantizationConfigobject, enabling fine-grained control over their quantization behavior.Added a new method
get_quantization_layer_structureto the Model class, intended for model authors to define the topology required for structure-aware quantization modes like GPTQ.Introduced a new utility function
should_quantize_layerto centralize the logic for determining if a layer should be quantized based on the provided filters.Enabled the serialization and deserialization of
QuantizationConfigobjects within Keras layers, allowing quantized models to be saved and loaded correctly.Modified the
AbsMaxQuantizerto allow specifying the quantization axis dynamically during the__call__method, rather than strictly defining it at initialization.Example:
Applies the default
AbsMaxQuantizerto both weights and activations.Disable activation quantization by setting the activation quantizer to
None.Customize the value range or other parameters for specific quantizers.
Adaptive Pooling layers
Added adaptive pooling operations
keras.ops.nn.adaptive_average_poolandkeras.ops.nn.adaptive_max_poolfor1D,2D, and3Dinputs. These operations transform inputs of varying spatial dimensions into a fixed target shape defined byoutput_sizeby dynamically inferring the required kernel size and stride. Added corresponding layers:keras.layers.AdaptiveAveragePooling1Dkeras.layers.AdaptiveAveragePooling2Dkeras.layers.AdaptiveAveragePooling3Dkeras.layers.AdaptiveMaxPooling1Dkeras.layers.AdaptiveMaxPooling2Dkeras.layers.AdaptiveMaxPooling3DNew features
keras.ops.numpy.array_splitop a fundamental building block for tensor parallelism.keras.ops.numpy.empty_likeop.keras.ops.numpy.ldexpop.keras.ops.numpy.vanderop which constructs a Vandermonde matrix from a 1-D input tensor.keras.distribution.get_device_countutility function for distribution API.keras.layers.JaxLayerandkeras.layers.FlaxLayernow support the TensorFlow backend in addition to the JAX backed. This allows you to embedflax.linen.Moduleinstances or JAX functions in your model. The TensorFlow support is based onjax2tf.OpenVINO Backend Support:
numpy.digitizesupport.numpy.diagsupport.numpy.isinsupport.numpy.vdotsupport.numpy.floor_dividesupport.numpy.rollsupport.numpy.multi_hotsupport.numpy.psnrsupport.numpy.empty_likesupport.Bug fixes and Improvements
attention_axesforMultiHeadAttentionlayers.Softmaxmask handling, aimed at improving numerical robustness, was based on a deep investigation led by Jaswanth Sreeram, who prototyped the solution with contributions from others.Normalizationlayer'sadaptmethod now supportsPyDatasetobjects, allowing for proper adaptation when using this data type.TPU Test setup
Configured the TPU testing infrastructure to enforce unit test coverage across the entire codebase. This ensures that both existing logic and all future contributions are validated for functionality and correctness within the TPU environment.
New Contributors
Full Changelog: keras-team/keras@v3.12.0...v3.13.0
v3.12.0: Keras 3.12.0Compare Source
Highlights
Keras has a new model distillation API!
You now have access to an easy-to-use API for distilling large models into small models while minimizing performance drop on a reference dataset -- compatible with all existing Keras models. You can specify a range of different distillation losses, or create your own losses. The API supports multiple concurrent distillation losses at the same time.
Example:
Keras supports GPTQ quantization!
GPTQ is now built into the Keras API. GPTQ is a post-training, weights-only quantization method that compresses a model to int4 layer by layer. For each layer, it uses a second-order method to update weights while minimizing the error on a calibration dataset.
Learn how to use it in this guide.
Example:
Better support for Grain datasets!
keras.utils.image_dataset_from_directoryandkeras.utils.text_dataset_from_directory. Specifyformat="grain"to return a Grain dataset instead of a TF dataset.New features
keras.layers.ReversibleEmbeddinglayer: an embedding layer that can also also project backwards to the input space. Use it with thereverseargument incall().opset_versioninmodel.export(). Argument specific toformat="onnx"; specifies the ONNX opset version.keras.ops.isinop.keras.ops.isneginf,keras.ops.isposinfops.keras.ops.isrealop.keras.ops.cholesky_inverseop and addupperargument inkeras.ops.cholesky.keras.ops.image.scale_and_translateop.keras.ops.hypotop.keras.ops.gcdop.keras.ops.kronop.keras.ops.logaddexp2op.keras.ops.viewop.keras.ops.unfoldop.keras.ops.jvpop.keras.ops.trapezoidop.Breaking changes
StringLookup&IntegerLookupnow save vocabulary loaded from file. Previously, when instantiating these layers from a vocabulary filepath, only the filepath would be saved when saving the layer. Now, the entire vocabulary is materialized and saved as part of the.kerasarchive.Security fixes
safe_mode: CVE-2025-12058 and CVE-2025-12060.New Contributors
Full Changelog: keras-team/keras@v3.11.0...v3.12.0
v3.11.3: Keras 3.11.3Compare Source
What's Changed
Full Changelog: keras-team/keras@v3.11.2...v3.11.3
v3.11.2: Keras 3.11.2Compare Source
What's Changed
New Contributors
Full Changelog: keras-team/keras@v3.11.1...v3.11.2
v3.11.1: Keras 3.11.1Compare Source
What's Changed
Full Changelog: keras-team/keras@v3.11.0...v3.11.1
v3.11.0: Keras 3.11.0Compare Source
What's Changed
fit()/evaluate()/predict().keras.ops.kaiserfunction.keras.ops.hanningfunction.keras.ops.cbrtfunction.keras.ops.deg2radfunction.keras.ops.layer_normalizationfunction to leverage backend-specific performance optimizations.Backend-specific changes
JAX backend
TensorFlow backend
Flattenlayer.OpenVINO backend
New Contributors
Full Changelog: keras-team/keras@v3.10.0...v3.11.0
v3.10.0: Keras 3.10.0Compare Source
New features
model.save(). It is controlled via themax_shard_sizeargument. Specifying this argument will split your Keras model weight file into chunks of this size at most. Useload_model()to reload the sharded files.keras.optimizers.Muonkeras.layers.RandomElasticTransformkeras.losses.CategoricalGeneralizedCrossEntropy(with functional versionkeras.losses.categorical_generalized_cross_entropy)axisargument toSparseCategoricalCrossentropylora_alphato all LoRA-enabled layers. If set, this parameter scales the low-rank adaptation delta during the forward pass.keras.activations.sparse_sigmoidkeras.ops.image.elastic_transformkeras.ops.anglekeras.ops.bartlettkeras.ops.blackmankeras.ops.hammingkeras.ops.view_as_complex,keras.ops.view_as_realPyTorch backend
TensorFlow backend
tf.RaggedTensorsupport toEmbeddinglayersynchronizationargumentOpenVINO backend
New Contributors
Full Changelog: keras-team/keras@v3.9.0...v3.10.0
[
v3.9.2](https://redirect.github.com/Configuration
📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.