Downloads · 30 days
0
Breakingbad6/onnx_resize_huntr
onnx_resize_huntr is a machine learning model from Breakingbad6. Use it for the machine learning task on the model card, and read the license before you ship it in a product.
Component: onnxruntime/core/providers/cpu/tensor/upsamplebase.h - ParseScalesData()
Downloads · 30 days
0
Access
Public
Updated May 8, 2026
Repo size
1.1 KB
Likes
0
Public
Click a slice to open those files.
.md6.5 KB · 51%
From the Hugging Face model README
Component: onnxruntime/core/providers/cpu/tensor/upsamplebase.h - ParseScalesData()
Type: Heap Buffer Overflow (CWE-122)
Entry Point: Model load → InferenceSession::Run() → Upsample<T>::Compute() → ParseScalesData()
Trigger: Loading and running a crafted .onnx model file containing a Resize op with oversized scales tensor
Impact: Heap corruption → potential Remote Code Execution
Affected Version: onnxruntime 1.23.2 (latest) and all prior versions with Resize op (opset >= 18)
In upsamplebase.h, ParseScalesData() performs a memcpy without verifying the destination buffer has sufficient capacity:
// upsamplebase.h line 543-551
ParseScalesData(const Tensor* scale, InlinedVector<float>& scales, int64_t rank) const {
const auto* scale_data = scale->Data<float>();
int64_t scales_size = scale->Shape().Size(); // attacker-controlled from model
ORT_RETURN_IF_NOT(scales_size > 0, "..."); // only checks > 0
if (scales.empty()) { // FALSE at runtime!
scales.resize(onnxruntime::narrow<size_t>(scales_size));
}
memcpy(scales.data(), scale_data, SafeInt<size_t>(scales_size) * sizeof(float)); // OVERFLOW
When called from Compute() at runtime (upsample.cc line 1390), scales is pre-initialized with input_dims.size() elements (e.g., 4 for NCHW input), making it non-empty. The resize() is skipped, but memcpy writes scales_size elements (attacker-controlled from model) into the undersized buffer.
The constructor caching condition at line 294:
if (get_scale && scale->Shape().Size() > 0 && ((opset < 18) || (rank > 0 && opset >= 18)))
When the model uses opset >= 18 and input X has no shape annotation (dynamic shape), rank = -1 at construction time. The caching condition fails, so scales_cached_ = false. At runtime, the vulnerable ParseScalesData path is taken.
.onnx model with a Resize op (opset 19)onnxruntime.InferenceSession()Compute() → ParseScalesData() → heap overflowmemcpy writes 1024+ bytes into a 16-byte buffer → heap corruptionpoc_resize_overflow.onnx — Malicious ONNX model filetrigger.py — Reproduction script (generates model + triggers crash)pip install onnxruntime==1.23.2 onnx numpy
python3 trigger.py
[+] Malicious model saved: poc_resize_overflow.onnx
scales tensor: 256 elements (expected: 4 for NCHW input)
opset: 19, input X shape: dynamic (rank unknown)
[*] Loading model: poc_resize_overflow.onnx
[*] Running inference...
scales_array capacity: ~16 bytes (4 floats)
memcpy size: 1024 bytes (256 floats)
expected: heap/stack corruption -> crash
Segmentation fault (core dumped)
In ParseScalesData(), always resize the destination buffer to match scales_size before memcpy:
// Fix: always ensure buffer is large enough, regardless of empty() state
if (scales.size() < static_cast<size_t>(scales_size)) {
scales.resize(onnxruntime::narrow<size_t>(scales_size));
}
memcpy(scales.data(), scale_data, SafeInt<size_t>(scales_size) * sizeof(float));
Or alternatively, validate scales_size against current buffer size:
ORT_RETURN_IF_NOT(scales_size <= static_cast<int64_t>(scales.size()),
"scales tensor size exceeds expected rank");