YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

TensorFlow SavedModel β€” CWE-22 Path Traversal via asset_file_def.filename

Severity: HIGH CWE-22 CVSS 7.5 Status: READY TO SUBMIT

Target Info

Field Value
Platform huntr.com
Repository tensorflow/tensorflow
Version 2.21.0 (latest master)
Max Payout $4,000
CWE CWE-22 β€” Improper Limitation of a Pathname to a Restricted Directory
CVSS v3.1 7.5 High (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)

Vulnerability

The TensorFlow SavedModel loader trusts asset_file_def[].filename values from the saved_model.pb protobuf without applying path sanitization. An attacker who crafts a malicious SavedModel can set asset filenames to path traversal strings (../../../etc/passwd) or absolute paths (/etc/passwd). When the model is loaded and its serving function is called, tf.io.read_file(asset_path) reads the arbitrary file and returns its contents as model output.

The save-side guard that the load side lacks:

# builder_impl.py:735 (SAVE β€” safe)
asset_filename = os.path.basename(asset_filepath)  # strips traversal

# asset.py:_deserialize_from_proto (LOAD β€” vulnerable)
filename = file_io.join(assets_dir, asset_file_def[index].filename)  # raw, no basename()

Root Cause

file_io.join() does not normalize .. components, and an absolute path in the second argument overrides the first:

  • file_io.join('/model/assets', '../../../etc/passwd') β†’ /model/assets/../../../etc/passwd (OS resolves on open)
  • file_io.join('/model/assets', '/etc/passwd') β†’ /etc/passwd (absolute override)

Reproduction

pip install tensorflow-cpu  # TF 2.21.0
python3 poc_tf_savedmodel.py

Expected output:

[!!!] CWE-22 PATH TRAVERSAL CONFIRMED
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
[!!!] /etc/hostname = 'ERIC-GACHARA'

Trigger Path

tf.saved_model.load(malicious_model_dir)
  β†’ _deserialize_from_proto() (asset.py)
    β†’ file_io.join(assets_dir, raw_filename_from_proto)   ← no basename()
      β†’ Asset(traversal_path)
        β†’ later: tf.io.read_file(asset.asset_path)
          β†’ reads /etc/passwd (or any file)

Deliverables

File Description
poc_tf_savedmodel.py Self-contained PoC β€” creates model, patches proto, reads /etc/passwd
report.md Full huntr-format report (Summary, Root Cause, Steps, Impact, Fix)
poc-evidence.html Styled HTML with verbatim terminal output and attack chain diagram
README.md This file

Suggested Fix

In Asset._deserialize_from_proto() and _get_asset_tensors():

raw_filename = asset_file_def[proto.asset_file_def_index].filename
safe_filename = os.path.basename(raw_filename)
if safe_filename != raw_filename:
    raise ValueError(f"Malicious asset filename detected: {repr(raw_filename)}")
filename = file_io.join(path_helpers.get_assets_dir(export_dir), safe_filename)

Huntr.com submission β€” Dark_photons β€” 2026-05-25

Downloads last month
3
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support