| # MLeap TensorFlow Bundle.ML Model Format PoC |
|
|
| This repository contains a local-only proof of concept for a model format vulnerability in TensorFlow-backed MLeap bundles. A malicious `.mleap` bundle can embed a TensorFlow `graph.pb` containing file operations and use MLeap TensorFlow metadata to execute those operations during normal inference. |
|
|
| - Target: `MLeap (.mleap) – Spark` |
| - Affected condition: `mleap-tensorflow` is on the classpath |
| - Tested commit: `027342cac5c96d6cb4f56046634a5f0487849a67` |
| - Tested version: `v0.24.0` |
| - Reproduced with: `eclipse-temurin:17-jdk-jammy` |
| - Image digest observed: `sha256:beabb759e6f9653c843958d1d1f5cecb881dfb85aa6081e2bef099ab1260344e` |
| - Container OS: Ubuntu 22.04.5 LTS, `linux/amd64` |
| - CPU assumption: AVX-capable x86_64 CPU; the test container reported `avx` and `avx2` |
| |
| ## Included Bundles |
| |
| - `mleap_tf_target.zip`: uses `nodes: ["write_poc"]` so MLeap calls TensorFlow `Runner.addTarget("write_poc")`, executing a `WriteFile` operation. |
| - `mleap_tf_control.zip`: has no `nodes` field; the fetched output has a TensorFlow control dependency on `WriteFile`. |
| - `mleap_tf_read.zip`: uses TensorFlow `ReadFile` and returns the local file content as a string prediction output. |
| |
| Each bundle contains: |
| |
| ```text |
| bundle.json |
| root/node.json |
| root/model.json |
| root/graph.pb |
| ``` |
| |
| ## Reproduce |
| |
| From this repository root: |
| |
| ```bash |
| mkdir -p /tmp/docker-no-creds |
| printf '{}' > /tmp/docker-no-creds/config.json |
| chmod +x run_linux_tensorflow_pocs.sh |
|
|
| DOCKER_CONFIG=/tmp/docker-no-creds docker run --rm --platform linux/amd64 \ |
| -v "$PWD":/audit \ |
| -w /audit \ |
| eclipse-temurin:17-jdk-jammy \ |
| /audit/run_linux_tensorflow_pocs.sh |
| ``` |
| |
| The script performs a fresh clone of MLeap, checks out `027342cac5c96d6cb4f56046634a5f0487849a67`, compiles `mleap-tensorflow`, generates the malicious bundles, loads them with public MLeap APIs, and calls normal `transform(...)`. |
| |
| ## Expected Output |
| |
| PoC A, `addTarget` file write: |
| |
| ```text |
| output=13.37 |
| proof_path=/tmp/mleap_tf_poc.txt |
| proof_exists=true |
| proof_contents=mleap tensorflow addTarget poc |
| ``` |
| |
| PoC B, control-dependency file write: |
| |
| ```text |
| output=13.37 |
| proof_path=/tmp/mleap_tf_poc_ctrl.txt |
| proof_exists=true |
| proof_contents=mleap tensorflow control dependency poc |
| ``` |
| |
| PoC C, file read into prediction output: |
| |
| ```text |
| output=mleap-secret-from-host |
| proof_path=/tmp/mleap_tf_secret.txt |
| proof_exists=true |
| proof_contents=mleap-secret-from-host |
| ``` |
| |
| ## Local Test Scope |
| |
| All testing is local and only touches `/tmp` inside the test container. No production systems are contacted. The PoCs do not require network access during inference, custom TensorFlow native operations, or attacker-provided code outside the `.mleap` model file. |
| |
| See `evidence.md` for bundle listings, extracted `root/model.json` files, graph strings, and full terminal output from the Docker reproduction. |
| |