Instructions to use unicuervo/keras-nested-lambda-modelscan-bypass with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Keras
How to use unicuervo/keras-nested-lambda-modelscan-bypass with Keras:
# Available backend options are: "jax", "torch", "tensorflow". import os os.environ["KERAS_BACKEND"] = "jax" import keras model = keras.saving.load_model("hf://unicuervo/keras-nested-lambda-modelscan-bypass") - Notebooks
- Google Colab
- Kaggle
| license: apache-2.0 | |
| tags: | |
| - keras | |
| - modelscan | |
| - model-file-vulnerability | |
| - security | |
| # Keras Native nested Lambda ModelScan bypass PoC | |
| This repository contains a benign proof-of-concept `.keras` model for a Huntr Model File Vulnerability report. | |
| ## Summary | |
| The file `nested_lambda.keras` contains a Keras `Lambda` layer nested inside an inner `Functional` model. | |
| ModelScan detects a top-level Keras `Lambda` layer, but this nested variant is reported as clean: | |
| ```text | |
| --- Summary --- | |
| No issues found! | |
| ``` | |
| However, recursive inspection of `config.json` shows the hidden Lambda: | |
| ```text | |
| [TOP_LEVEL_LAMBDAS] [] | |
| [RECURSIVE_LAMBDA_COUNT] 1 | |
| [RECURSIVE_LAMBDA] hidden_lambda at $.config.layers[1].config.layers[1] | |
| ``` | |
| Keras itself recognizes the nested Lambda as unsafe during default loading and blocks it with `safe_mode=True`. | |
| When the same model is loaded with `safe_mode=False`, the nested Lambda is deserialized and changes model behavior. This PoC only performs benign output manipulation and returns `1337.0` for input `5.0`. | |
| ## Files | |
| - `nested_lambda.keras`: benign PoC model file. | |
| - `reproduce.py`: local reproduction script. | |
| - `requirements.txt`: dependency list. | |
| - `generate_model.py`: optional script to regenerate the PoC model. | |
| ## Reproduction | |
| Install dependencies: | |
| ```bash | |
| python -m venv .venv | |
| source .venv/bin/activate | |
| python -m pip install -r requirements.txt | |
| ``` | |
| Run ModelScan: | |
| ```bash | |
| modelscan -p nested_lambda.keras | |
| ``` | |
| Expected result: | |
| ```text | |
| No issues found! | |
| ``` | |
| Run the local reproduction: | |
| ```bash | |
| KERAS_BACKEND=tensorflow python reproduce.py | |
| ``` | |
| Expected result: | |
| ```text | |
| [TOP_LEVEL_LAMBDAS] [] | |
| [RECURSIVE_LAMBDA_COUNT] 1 | |
| [RECURSIVE_LAMBDA] hidden_lambda at $.config.layers[1].config.layers[1] | |
| [DEFAULT_LOAD_BLOCKED] ValueError | |
| Requested the deserialization of a `Lambda` layer whose `function` is a Python lambda. | |
| [UNSAFE_LOAD_OK] | |
| [OUTPUT] [[1337.0]] | |
| ``` | |
| ## Security impact | |
| A scanner or model registry relying on ModelScan may incorrectly classify a `.keras` model as clean even though it contains an unsafe Lambda layer. | |
| This is a scanner bypass / false negative. The PoC does not claim code execution under Keras default `safe_mode=True`. Keras blocks the nested Lambda by default. The impact is that ModelScan fails to detect the same unsafe construct that Keras later identifies and blocks. | |
| If a downstream consumer trusts the clean ModelScan result and loads the model with `safe_mode=False` or globally enables unsafe deserialization, the hidden Lambda is deserialized and can manipulate model behavior. | |