VYPR
High severityNVD Advisory· Published Mar 11, 2025· Updated Jul 24, 2025

Arbitrary Code Execution via Crafted Keras Config for Model Loading

CVE-2025-1550

Description

The Keras Model.load_model function permits arbitrary code execution, even with safe_mode=True, through a manually constructed, malicious .keras archive. By altering the config.json file within the archive, an attacker can specify arbitrary Python modules and functions, along with their arguments, to be loaded and executed during model loading.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Arbitrary code execution in Keras Model.load_model via malicious .keras archive even with safe_mode=True.

The vulnerability in Keras's Model.load_model function allows arbitrary code execution when loading a crafted .keras archive, even with safe_mode=True. The root cause lies in the _retrieve_class_or_fn function used during deserialization, which did not restrict the Python modules that could be imported. By altering config.json within the archive, an attacker can specify arbitrary Python modules and functions to be executed during model loading [1][2].

Exploitation requires only that a user loads a malicious .keras file. No authentication or special network position is needed, making any application that loads Keras models from untrusted sources vulnerable. The attack surface includes machine learning pipelines, model hubs, and any service that accepts user-uploaded models [2].

Successful exploitation gives an attacker full arbitrary code execution in the context of the user or process loading the model. This can lead to data exfiltration, privilege escalation, or complete system compromise [2].

The Keras team has addressed this issue in commit e67ac8f by adding checks to _retrieve_class_or_fn to limit imports to only keras.src modules and by validating deserialized objects [4]. Users should update to the latest Keras version containing this fix. No effective workaround exists other than avoiding loading models from untrusted sources [1][4].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
kerasPyPI
>= 3.0.0, < 3.9.03.9.0

Affected products

5

Patches

1
e67ac8ffd0c8

Add checks to deserialization. (#20751)

https://github.com/keras-team/kerashertschuhJan 12, 2025via ghsa
2 files changed · +18 16
  • keras/src/models/functional.py+6 0 modified
    @@ -19,6 +19,7 @@
     from keras.src.ops.function import make_node_key
     from keras.src.ops.node import KerasHistory
     from keras.src.ops.node import Node
    +from keras.src.ops.operation import Operation
     from keras.src.saving import serialization_lib
     from keras.src.utils import tracking
     
    @@ -523,6 +524,11 @@ def process_layer(layer_data):
                 layer = serialization_lib.deserialize_keras_object(
                     layer_data, custom_objects=custom_objects
                 )
    +        if not isinstance(layer, Operation):
    +            raise ValueError(
    +                "Unexpected object from deserialization, expected a layer or "
    +                f"operation, got a {type(layer)}"
    +            )
             created_layers[layer_name] = layer
     
             # Gather layer inputs.
    
  • keras/src/saving/serialization_lib.py+12 16 modified
    @@ -783,22 +783,18 @@ def _retrieve_class_or_fn(
     
             # Otherwise, attempt to retrieve the class object given the `module`
             # and `class_name`. Import the module, find the class.
    -        try:
    -            mod = importlib.import_module(module)
    -        except ModuleNotFoundError:
    -            raise TypeError(
    -                f"Could not deserialize {obj_type} '{name}' because "
    -                f"its parent module {module} cannot be imported. "
    -                f"Full object config: {full_config}"
    -            )
    -        obj = vars(mod).get(name, None)
    -
    -        # Special case for keras.metrics.metrics
    -        if obj is None and registered_name is not None:
    -            obj = vars(mod).get(registered_name, None)
    -
    -        if obj is not None:
    -            return obj
    +        if module == "keras.src" or module.startswith("keras.src."):
    +            try:
    +                mod = importlib.import_module(module)
    +                obj = vars(mod).get(name, None)
    +                if obj is not None:
    +                    return obj
    +            except ModuleNotFoundError:
    +                raise TypeError(
    +                    f"Could not deserialize {obj_type} '{name}' because "
    +                    f"its parent module {module} cannot be imported. "
    +                    f"Full object config: {full_config}"
    +                )
     
         raise TypeError(
             f"Could not locate {obj_type} '{name}'. "
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.