TensorFlow SavedModel Dataset I/O ModelScan Bypass PoC
Benign security proof-of-concept for a ModelScan TensorFlow SavedModel scanner/runtime mismatch.
Summary
This SavedModel contains TensorFlow dataset file I/O ops that execute during inference:
TextLineDatasetreads a local text file and returns its first line.DatasetToTFRecordwrites a TFRecord file and overwrites the target path.
ModelScan 0.8.8 scans saved_model.pb and fingerprint.pb, then reports zero issues. The scanner's TensorFlow SavedModel unsafe-op list covers ReadFile and WriteFile, but does not flag these dataset I/O ops even though the runtime consumes them.
This is not a TensorFlow runtime CVE claim. TensorFlow SavedModel should be treated as packaged code. The issue is that a clean ModelScan result can miss artifact-carried filesystem behavior that executes when the model is served or invoked.
Tested Versions
tensorflow==2.21.0modelscan==0.8.8- Python 3.12.3
- Linux
Files
savedmodel_dataset_io/: PoC TensorFlow SavedModel artifact.verify_poc.py: Loads the SavedModel, invokes the signatures, and validates benign marker read/write effects.modelscan_dataset_io.json: Captured ModelScan 0.8.8 JSON output.runtime_dataset_io.json: Captured TensorFlow runtime validation output.dataset_io_graph_ops.txt: Extracted op names fromsaved_model.pb.dataset_io_sha256sums.txt: SHA256 hashes for the artifact files.
Reproduce
python -m venv .venv
. .venv/bin/activate
pip install tensorflow==2.21.0 modelscan==0.8.8
python verify_poc.py
modelscan -p savedmodel_dataset_io -r json --show-skipped
Expected runtime result:
fixed_first_lineandparameterized_first_lineequalTFSM_TEXTLINE_DATASET_MARKER_2026.fixed_recordandparameterized_recordequalTFSM_DATASET_TO_TFRECORD_MARKER_2026.- All
*_matchedfields aretrue.
Expected scanner result:
{
"summary": {
"total_issues": 0,
"total_issues_by_severity": {
"LOW": 0,
"MEDIUM": 0,
"HIGH": 0,
"CRITICAL": 0
},
"scanned": {
"total_scanned": 2,
"scanned_files": ["fingerprint.pb", "saved_model.pb"]
}
},
"issues": [],
"errors": []
}
Graph Ops
The graph contains the relevant file I/O ops and does not contain ReadFile or WriteFile:
DatasetToTFRecord
TextLineDataset
dataset_io_graph_ops.txt contains the full extracted op list.
Artifact Hashes
153485cab9a8aa350d4e47336ff6888ac073facfc554ac50d6fe77b7e7b71165 savedmodel_dataset_io/saved_model.pb
d85300d23aefe12eb26725b97cbc79917415dc824d273142d638f1f31f6be030 savedmodel_dataset_io/fingerprint.pb
849c94eceaa927b215674c9cbda5393d2bfabebed1605d87f28de06b221a1063 savedmodel_dataset_io/variables/variables.data-00000-of-00001
4eeeb44652a18698ebcb7be0d364bfe58c3d9d19b5d7cab9910cccbc9bfdab1d savedmodel_dataset_io/variables/variables.index
Impact
If a model registry or deployment pipeline treats ModelScan's clean result as sufficient before loading or serving an untrusted SavedModel, the model can still perform local filesystem reads and TFRecord writes during inference.
The PoC keeps all effects benign and local. It does not execute shell commands, access credentials, persist, or perform network activity.
Limitations
- This is a ModelScan detection gap, not a TensorFlow runtime bug.
- The write primitive is demonstrated with TFRecord-formatted marker data.
- Real impact depends on a workflow that scans untrusted SavedModels and then serves or invokes them based on the scanner result.
Suggested Mitigation
Do not classify every public tensorflow.raw_ops op as safe by default. Expand SavedModel scanning to cover dataset and filesystem-adjacent ops such as TextLineDataset, TFRecordDataset, DatasetToTFRecord, CSVDataset*, SqlDataset, SaveDataset, SnapshotDataset*, summary writers, and related filesystem configuration ops, or move toward a serving-safe allowlist.