Instructions to use j0hndo/tensorrt-rproi-createplugin-onnx-oob-poc with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- TensorRT
How to use j0hndo/tensorrt-rproi-createplugin-onnx-oob-poc with TensorRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
You need to agree to share your contact information to access this model
This repository is publicly accessible, but you have to accept the conditions to access its files and content.
These files are a security-research proof-of-concept that triggers memory corruption in NVIDIA TensorRT's ONNX parser. They are NOT functional models. Do not load them outside an isolated, disposable sandbox. Access is granted for coordinated-disclosure review only.
Log in or Sign Up to review the conditions and access this model content.
- Security research PoC β gated; access granted to protectai-bot for review
Security research PoC β gated; access granted to protectai-bot for review
This repository contains malicious ONNX model files used as a proof-of-concept for a memory-corruption vulnerability in NVIDIA TensorRT's ONNX parser. It is uploaded as a gated repo for coordinated vulnerability disclosure through the huntr.com (ProtectAI) AI/ML bounty program. Review access has been granted to protectai-bot.
This is not a usable machine-learning model. Loading these files is the exploit.
β οΈ What these files are β read before doing anything
The two .onnx files in this repository are crafted to corrupt memory inside TensorRT's ONNX import path. When TensorRT's OnnxParser (or trtexec) parses one of these files with the standard plugin library registered (initLibNvInferPlugins), control reaches the deprecated-but-still-registered RPROI_TRT plugin's createPlugin routine, which reads attacker-controlled element counts with no upper bound and walks off the end of a heap buffer.
Do NOT load these files outside an isolated, disposable sandbox. Treat them as live malware against the TensorRT process:
- Parsing the OOB-read file reliably reads past a heap allocation. Under a normal release build this is an over-read that may segfault the process or silently leak adjacent heap contents; under an AddressSanitizer build it aborts immediately.
- The integer-overflow file is designed to drive an undersized allocation followed by an out-of-bounds write (analytical leg β see caveats). Do not run it against anything you care about.
Run only inside a throwaway container/VM with no sensitive data and no network access you care about.
The two model files
| File | Crafted attributes | What it triggers |
|---|---|---|
rproi_oob_read.onnx |
RPROI_TRT node with anchorsRatioCount = 64 (INT) but anchorsRatios = [0.5] (1 float) |
Heap out-of-bounds READ (CWE-125) in RPROIPluginCreator::createPlugin. The loop runs 64 iterations over a 1-element float buffer. This is the dynamically ASAN-confirmed leg, crashing at nvFasterRCNNPlugin.cpp:482. |
rproi_intoverflow.onnx |
RPROI_TRT node with anchorsRatioCount = 1, anchorsScaleCount = 1073741825 (2Β³β°+1) |
Integer-overflow β out-of-bounds WRITE (CWE-190 β CWE-787). The unbounded counts feed 4 * anchorsRatioCount * anchorsScaleCount * sizeof(float) into the device allocation as a signed-int product that overflows to a small positive value, yielding an undersized buffer that is then overrun. This leg is static/analytical β it is NOT dynamically reproduced in this research (see caveats). |
Both files were produced by poc/craft_rproi_onnx.py (included). The core trick is that an ONNX FLOATS attribute's element count and the separate INT count attribute are set independently by the attacker, and the parser never reconciles them.
Root cause (source, with file:line)
Component: plugin/nvFasterRCNN/nvFasterRCNNPlugin.cpp, function RPROIPluginCreator::createPlugin.
The scalar count is read with only a type check, no range check:
// nvFasterRCNNPlugin.cpp:453
PLUGIN_VALIDATE(fields[i].type == PluginFieldType::kINT32);
params.anchorsRatioCount = *(static_cast<int32_t const*>(fields[i].data)); // attacker INT, unbounded
It is then used as the loop bound over an independently-sized float buffer:
// nvFasterRCNNPlugin.cpp:478-484
anchorsRatios.reserve(params.anchorsRatioCount);
float const* ratios = static_cast<float const*>(fields[i].data); // buffer holds fields[i].length floats
for (int32_t j = 0; j < params.anchorsRatioCount; ++j) // bound = attacker INT
{
anchorsRatios.push_back(*ratios); // line 482: OOB READ when anchorsRatioCount > fields[i].length
ratios++;
}
fields[i].length is the real ONNX element count (set by copyField, onnxOpImporters.cpp:7263-7270), and the FallbackPluginImporter path that builds the PluginFieldCollection never clamps it against the creator-declared length of 1. So anchorsRatioCount = 64 over a 1-float buffer reads 63 floats past the allocation. The identical pattern exists for anchorsScaleCount / anchorsScales (lines 486-496), and both unbounded counts feed the unchecked device-allocation multiplication (4 * anchorsRatioCount * anchorsScaleCount * sizeof(float), near line 43) that overflows.
A TODO in the same file (lines 384-386) notes the size information for the float arrays was "not available at this point" β the bound was never enforced.
Reproduction
There are two ways to reproduce. (B) is the cleanest deterministic evidence and is what produced the quoted ASAN crash below.
(A) End-to-end through the real TensorRT ONNX parser
createPlugin runs during the CPU-side ONNX import, before any GPU kernel is launched, so reaching the bug does not require a full engine build.
pip install tensorrt # provides the real OnnxParser + plugin library
# For a deterministic ASAN stack trace, build TensorRT OSS with -DSANITIZE=address
# and use that libnvinfer_plugin / trtexec.
python poc/reproduce_tensorrt.py rproi_oob_read.onnx
reproduce_tensorrt.py calls trt.init_libnvinfer_plugins(logger, ""), builds an OnnxParser, and calls parser.parse() on the crafted file β createPlugin is invoked during import. Under an ASAN-instrumented OSS build you get a heap-buffer-overflow READ originating in nvFasterRCNNPlugin.cpp. Under a stock release build, a small over-read (e.g. anchorsRatioCount=64) may silently read adjacent heap; a large count makes the loop walk into unmapped memory and reproducibly SIGSEGV the TensorRT process. Equivalently: trtexec --onnx=rproi_oob_read.onnx.
(B) Source-level ASAN reproduction of the genuine translation unit
This compiles NVIDIA's own nvFasterRCNNPlugin.cpp under AddressSanitizer using small CUDA-header shims (CUDA is only needed to satisfy includes; every stubbed symbol is reached only after the OOB, so the vulnerable loop is unmodified NVIDIA code). It is provided under poc/source_asan/:
cd poc/source_asan
./build_realtu.sh # compiles the genuine nvFasterRCNNPlugin.cpp + checkMacros TUs
# under -fsanitize=address, then runs the attack + negative control
Expected output (attack case): an AddressSanitizer heap-buffer-overflow READ of size 4 whose crashing frame is:
#3 nvinfer1::plugin::RPROIPluginCreator::createPlugin(...)
refs/tensorrt/plugin/nvFasterRCNN/nvFasterRCNNPlugin.cpp:482
The negative control (anchorsRatioCount == anchorsRatios length == 1) exits cleanly with no ASAN error, proving the crash is specific to the count-vs-length mismatch and not a build artifact.
Quoted excerpt β genuine-TU ASAN crash (verbatim)
From the real-translation-unit attack run (anchorsRatioCount=64, buffer_len=1):
==779==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000000014 ...
READ of size 4 at 0x502000000014 thread T0
#2 std::vector<float, std::allocator<float> >::push_back(float const&)
#3 nvinfer1::plugin::RPROIPluginCreator::createPlugin(char const*, nvinfer1::PluginFieldCollection const*)
refs/tensorrt/plugin/nvFasterRCNN/nvFasterRCNNPlugin.cpp:482
0x502000000014 is located 0 bytes to the right of 4-byte region [0x502000000010,0x502000000014)
allocated by thread T0 here:
#0 operator new[](unsigned long)
==779==ABORTING
The read lands exactly 0 bytes past the new float[1] (4-byte) allocation β the first float beyond the buffer β at the genuine NVIDIA source line.
Affected versions
TensorRT builds that ship and register the RPROI_TRT plugin. The missing bound was confirmed present across at least TRT 10.13 through 11.0 (HEAD as of 2026-06-02) and is likely present in earlier releases. nvFasterRCNN is marked DEPRECATED in plugin/README.md but remains compiled and unconditionally registered by initLibNvInferPlugins (inferPlugin.cpp:203); no removal has been implemented.
CVSS (CVSS 3.1)
- OOB read (CWE-125) β primary, local model-loading:
AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H= 6.1 (Medium). Serving-endpoint vector (auto-parsing untrusted uploads):AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H= 8.2 (High).C:Lis an upper bound for potential info-leak and is not demonstrated end-to-end; expectC:N. - Integer-overflow OOB write (CWE-190 β CWE-787) β primary:
AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H= 7.1 (High). Serving-endpoint vector:AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H= 9.1 (Critical). Written content is computed anchor geometry, not attacker-controlled bytes β a reliable heap-corruption/DoS primitive whose RCE potential is unproven.
CWE
- CWE-125 β Out-of-bounds Read (dynamically confirmed)
- CWE-190 β Integer Overflow or Wraparound β CWE-787 β Out-of-bounds Write (static/analytical)
Responsible disclosure
This research follows coordinated disclosure. These files contain no weaponized payload beyond the minimum needed to demonstrate the memory-safety defect, and no exploit chain for code execution is provided. The package is shared with ProtectAI/huntr for triage and onward coordination with the NVIDIA vendor security team. Please do not redistribute the crafted models outside the disclosure process.
Contents of this repo:
README.md this model card
poc/
βββ craft_rproi_onnx.py builds the two malicious .onnx files
βββ reproduce_tensorrt.py end-to-end repro via the real TensorRT OnnxParser
βββ source_asan/
βββ build_realtu.sh genuine-TU ASAN reproduction (crash at nvFasterRCNNPlugin.cpp:482)
rproi_oob_read.onnx OOB read PoC (count=64 vs 1-float buffer)
rproi_intoverflow.onnx integer-overflow PoC (count = 2^30+1)
- Downloads last month
- -