| # VULN-016: Arbitrary File Read via ONNX External Data Path Traversal in TensorRT | |
| ## Vulnerability | |
| TensorRT's ONNX parser (`libnvonnxparser`) allows absolute file paths in the `external_data.location` field of ONNX TensorProto initializers. When a victim loads a malicious ONNX model, arbitrary files from their filesystem are read as model weights and embedded into the compiled TensorRT engine. | |
| **CWE-22**: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') | |
| ## Severity | |
| **Critical (CVSS 3.1: 9.1)** | |
| ## Root Cause | |
| `normalizePath()` in `weightUtils.cpp` blocks `../` relative directory traversal but does NOT reject absolute paths like `C:/Windows/win.ini` or `/etc/passwd`. The absolute path passes through all validation and is used directly in `CreateFileMapping()` / `mmap()`. | |
| ## Affected Versions | |
| - TensorRT 10.16.0.29 (tested) | |
| - Likely all TensorRT versions with ONNX external data support | |
| ## Impact | |
| An attacker can craft a ~200-byte ONNX model that, when loaded by TensorRT: | |
| 1. Reads arbitrary files from the victim's filesystem | |
| 2. Embeds file contents into the compiled TensorRT engine | |
| 3. Exposes stolen data through inference output | |
| Attack scenarios: steal SSH keys, cloud credentials, application configs, proprietary models. | |
| ## Files | |
| | File | Description | | |
| |------|-------------| | |
| | `poc_windows.onnx` | PoC model targeting `C:/Windows/win.ini` (Windows) | | |
| | `poc_linux.onnx` | PoC model targeting `/etc/hostname` (Linux) | | |
| | `reproduce.py` | Reproduction script ? loads PoC model and extracts stolen file contents | | |
| | `create_malicious_model.py` | Tool to create custom malicious models targeting any file | | |
| ## Reproduction | |
| ```bash | |
| # 1. Install requirements | |
| pip install tensorrt numpy onnx | |
| # 2. Run the PoC (Windows) | |
| python reproduce.py poc_windows.onnx | |
| # 3. Or create a custom exploit model | |
| python create_malicious_model.py C:/Users/victim/.ssh/id_rsa exploit.onnx 4096 | |
| python reproduce.py exploit.onnx | |
| ``` | |
| ## Expected Output | |
| ``` | |
| [*] Loading model: poc_windows.onnx | |
| [+] Parse succeeded - external file was read as model weights! | |
| [+] Engine built - file contents now embedded in TensorRT engine | |
| [+] Extracted 92 bytes from target file: | |
| ---------------------------------------- | |
| ; for 16-bit app support | |
| [fonts] | |
| [extensions] | |
| [mci extensions] | |
| [files] | |
| [Mail] | |
| MAPI=1 | |
| ---------------------------------------- | |
| ``` | |
| ## Verified Reads | |
| | Target File | Result | | |
| |---|---| | |
| | `C:/Windows/System32/kernel32.dll` | Read successful (4096 bytes) | | |
| | `C:/Windows/System32/ntdll.dll` | Read successful (4096 bytes) | | |
| | `C:/Windows/win.ini` | Read successful ? byte-for-byte content match verified | | |
| ## Suggested Fix | |
| In `parseExternalWeights()`, reject absolute paths: | |
| ```cpp | |
| std::string normalizedFile = normalizePath(file); | |
| if (normalizedFile.find("../") != std::string::npos) return false; | |
| // ADD: reject absolute paths | |
| if (!normalizedFile.empty() && (normalizedFile[0] == '/' || normalizedFile[0] == '\\')) | |
| return false; | |
| if (normalizedFile.size() > 1 && normalizedFile[1] == ':') | |
| return false; | |
| ``` | |
| ## Related CVEs | |
| - CVE-2022-25882: ONNX library path traversal via external_data | |
| - CVE-2024-27318: Bypass of CVE-2022-25882 fix | |
| - CVE-2024-5187: ONNX path traversal via tar | |
| - CVE-2025-51480: ONNX save_external_data path traversal | |
| TensorRT's C++ parser has its own independent implementation that does not inherit fixes from the ONNX Python library. | |