Repository navigation
Description
Summary
This repository vendors ultralytics 8.0.120 inside a vendored sub-project (models/MobileSAMv2/ultralytics/…), and that copy still parses ONNX model metadata with eval(). Loading an untrusted .onnx therefore executes attacker-chosen Python in the loading process — before any inference, and before the pickle-free path that leads people to choose ONNX in the first place.
Affected version
- bundled
ultralytics8.0.120 (insidemodels/MobileSAMv2/) - repository
HEAD5888e722876511f177e8e762498a7986753b7f7d(last push 2025-09-08; re-checked 2026-09-29, unchanged) models/MobileSAMv2/ultralytics/nn/autobackend.py:132—metadata = session.get_modelmeta().custom_metadata_mapmodels/MobileSAMv2/ultralytics/nn/autobackend.py:278—metadata[k] = eval(v)- file sha256
55a5363f49f0a63d18d07c01264fabd7e3fab7cfbdeb9125e5bf43d642b0c4d8(byte-identical to the fileCASIA-LMC-Lab/FastSAMships at the same 8.0.120 vintage)
Steps to reproduce
- Build a minimal
.onnxwhosemetadata_propscarries a constant-only expression forimgsz(for example"7*191"). - Load it through the vendored code:
AutoBackend(weights="model.onnx")— the library's ordinary action for a model file. - The expression runs while the constructor executes, and
imgszcomes back as[640, 640]— a value onlyeval()of the stored string could produce.
Expected behavior
metadata_props is inert data; imgsz / names / kpt_shape are parsed, not executed.
Actual behavior
The stored strings are evaluated with the module globals and unrestricted builtins. Between the read at :132 and the eval at :278 there is no allow-list, no regex, no restricted builtins and no try/except. imgsz, names and kpt_shape are exactly the keys a genuine exported model carries, and ONNX Runtime places no constraint on metadata_props.
How it was verified
Code-level: the source and sink lines above were re-read live at this repository's default branch HEAD on 2026-09-29. Execution-level: the exact bytes this repository vendors were executed on 2026-09-29 — the official PyPI ultralytics 8.0.120 wheel, whose nn/autobackend.py is byte-identical to the vendored file (same sha256 55a5363f…), was driven through AutoBackend(weights=…) with a harmless sentinel expression in the metadata (it only writes one inert marker file) and a benign-metadata negative control: the marker appears for the attack artifact, never for the control. A sibling vendored copy of the same lineage (iMoonLab/yolov13, 8.3.63) was additionally driven end-to-end through the product's own yolo predict CLI. No exploit string is included here; the sentinels are harmless integer constants — no network, no shell, no persistence.
Impact
Arbitrary code execution with the privileges of the loading process — anything that process can read or write (datasets, checkpoints, hub tokens, cloud credentials), plus the ability to terminate or hang it.
Suggested fix
Apply the one-line upstream fix at models/MobileSAMv2/ultralytics/nn/autobackend.py:278, or resync the vendored sub-project to >= 8.3.234. ast is already imported in the file:
- metadata[k] = eval(v)
+ metadata[k] = ast.literal_eval(v)Longer term it may be worth depending on the PyPI ultralytics package (>= 8.3.234) instead of vendoring a copy of a copy.
Activity