MLeap raw TensorFlow graph.pb executes file I/O ops while scanner reports clean

Submission

  • Data format: MLeap Bundle.ML with TensorFlow root/graph.pb
  • Suggested title: MLeap raw TensorFlow graph.pb executes file I/O ops while scanner reports clean
  • Severity: High
  • Impact: model-carried TensorFlow ReadFile and WriteFile operations execute during MLeap inference while the MLeap/raw-GraphDef scan path reports zero issues
  • Affected runtime verified: ml.combust.mleap:mleap-tensorflow_2.13:0.24.0
  • Scanner verified: ModelScan 0.8.8
  • Not claimed: arbitrary native code execution

Executive summary

MLeap Bundle.ML can store a TensorFlow model as a raw GraphDef at root/graph.pb. MLeap's TensorflowTransformer imports that graph and executes it during normal transform/inference. ModelScan scans the same nested root/graph.pb using its TensorFlow-op scanner but reports zero issues for the raw GraphDef/MLeap bundle form, even when the graph contains TensorFlow file I/O operations that are considered unsafe and are flagged when wrapped as a SavedModel control.

This repository includes two benign PoCs:

  • readfile/: reads a local marker file and returns the marker string as model output.
  • writefile/: writes a benign local marker file during inference.

The dangerous behavior is carried by the MLeap model artifact. The reviewer does not run attacker code outside model loading/inference; the verifier only loads the bundle and calls transform.

Why this is security-relevant

Model scanning and model runtime disagree about the same TensorFlow graph. A repository/service could accept an MLeap bundle as scanner-clean while MLeap later executes TensorFlow file I/O ops from the bundle during inference. The ReadFile primitive demonstrates local file disclosure into a model output, and the WriteFile primitive demonstrates file creation/modification on the runtime host. The PoCs use harmless marker paths and marker strings.

Root cause

There are two parts:

  1. Runtime: MLeap imports a raw GraphDef from root/graph.pb and executes nodes listed by the MLeap model JSON.
  2. Scanner mismatch: ModelScan recognizes the nested root/graph.pb and runs SavedModelTensorflowOpScan, but the raw GraphDef form is not interpreted the same way as a SavedModel protobuf. The equivalent SavedModel control is flagged as HIGH for ReadFile, while the MLeap bundle/raw GraphDef path reports zero issues.

Repository contents

readfile/mleap_tf_readfile_bundle.zip                 MLeap ReadFile bundle
readfile/readfile_graph.pb                            raw GraphDef embedded in the bundle
readfile/readfile_saved_model.pb                      SavedModel control containing the same op
readfile/verify_poc.scala                             verifier used to load and transform the bundle
readfile/mleap_tf_readfile_runtime_output.txt         runtime output showing marker disclosure
readfile/modelscan_*                                  scanner outputs

writefile/mleap_tf_writefile_bundle.zip               MLeap WriteFile bundle
writefile/writefile_graph.pb                          raw GraphDef embedded in the bundle
writefile/verify_poc.scala                            verifier used to load and transform the bundle
writefile/runtime_output.txt                          runtime output showing marker write
writefile/modelscan_*                                 scanner outputs
SHA256SUMS.txt                                        hash manifest

Reproduction

Install Java, Coursier, and ModelScan, then fetch MLeap TensorFlow:

hf download pragnyanramtha/mleap-tf-raw-graphdef-unsafe-ops-poc --local-dir mleap-poc

COURSIER_CACHE=/tmp/mleap-coursier-cache \
  cs fetch --classpath ml.combust.mleap:mleap-tensorflow_2.13:0.24.0 > mleap-tf.classpath

ReadFile runtime proof:

cd mleap-poc/readfile
mkdir -p classes /tmp/mleap-readfile
printf MLEAP_TF_READFILE_MARKER > /tmp/mleap-readfile/source.txt
CP=$(cat ../../mleap-tf.classpath)
cs launch scalac:2.13.16 -- -classpath "$CP" -d classes verify_poc.scala
java -cp "classes:$CP" LoadRunMLeapTfReadBundle \
  "jar:file:$PWD/mleap_tf_readfile_bundle.zip" \
  /tmp/mleap-readfile/source.txt

Expected output:

LOAD_OK root=ml.combust.mleap.tensorflow.TensorflowTransformer
INFER_OK outputs=1
OUTPUT_0_RAW=MLEAP_TF_READFILE_MARKER

WriteFile runtime proof:

cd ../writefile
mkdir -p classes /tmp/mleap-writefile
CP=$(cat ../../mleap-tf.classpath)
cs launch scalac:2.13.16 -- -classpath "$CP" -d classes verify_poc.scala
java -cp "classes:$CP" LoadRunMLeapTfBundle \
  "jar:file:$PWD/mleap_tf_writefile_bundle.zip" \
  /tmp/mleap-writefile/marker.txt

Expected output:

LOAD_OK root=ml.combust.mleap.tensorflow.TensorflowTransformer
INFER_OK outputs=0
MARKER_EXISTS=true
MLEAP_TF_WRITEFILE_MARKER

Scanner proof

Run ModelScan on the MLeap bundle and the SavedModel control:

modelscan -p readfile/mleap_tf_readfile_bundle.zip -r json --show-skipped
modelscan -p readfile/readfile_graph.pb -r json --show-skipped
modelscan -p readfile/readfile_saved_model.pb -r json --show-skipped

Observed bundle/raw-GraphDef result:

Scanning mleap_tf_readfile_bundle.zip:root/graph.pb using modelscan.scanners.SavedModelTensorflowOpScan
total_issues: 0
scanned_files: ["mleap_tf_readfile_bundle.zip:root/graph.pb"]

Observed SavedModel control:

total_issues_by_severity: HIGH: 1
description: Use of unsafe operator 'ReadFile' from module 'Tensorflow'
severity: HIGH

The captured scanner outputs are included in each subdirectory.

Hashes

07e435e47b0068ca6fcd7d760262d122da419c642e3399949df730799e9eb4a6  readfile/mleap_tf_readfile_bundle.zip
8f0e9f6b5f385ef4beabcdd52a3e9274589ba821ebd1a17cef0bc2f2e1d98cf9  readfile/readfile_graph.pb
1c18b89493fa9b2d3f5654093caafda67006a93c3a2826ac32306e51c5f1c2a9  readfile/readfile_saved_model.pb
2cd2e3dae5ddea26c9cfea76b2af22d615401f9ee77dd33cc639df62dc2c5971  writefile/mleap_tf_writefile_bundle.zip

Suggested fix

Model scanners should parse raw TensorFlow GraphDef files embedded inside MLeap bundles as GraphDef, not only SavedModel-like protobufs. MLeap deployments should reject or sandbox TensorFlow graphs containing file I/O ops unless explicitly allowed. The runtime can also gate dangerous TensorFlow ops before importing/executing root/graph.pb.

Limitations

The PoCs use benign marker files. This report demonstrates model-carried local file read/write primitives and scanner/runtime mismatch, not arbitrary native code execution.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support