YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

ONNX Runtime Resize Op: Heap Buffer Overflow via ParseScalesData

Vulnerability Summary

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)

Root Cause

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.

Why Scales Are Not Cached (Trigger Condition)

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.

Attack Vector

  1. Attacker crafts a .onnx model with a Resize op (opset 19)
  2. Input X has no shape annotation (common in dynamic-shape models)
  3. Scales tensor is embedded as initializer with 256+ elements (vs expected 4 for NCHW)
  4. Victim loads model with onnxruntime.InferenceSession()
  5. Victim runs inference → Compute()ParseScalesData() → heap overflow
  6. memcpy writes 1024+ bytes into a 16-byte buffer → heap corruption

Files

  • poc_resize_overflow.onnx — Malicious ONNX model file
  • trigger.py — Reproduction script (generates model + triggers crash)

Reproduction

pip install onnxruntime==1.23.2 onnx numpy
python3 trigger.py

Expected Output

[+] 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)

Environment

  • OS: Ubuntu 22.04 (WSL2) / tested on Linux x86_64
  • Python: 3.10
  • onnxruntime: 1.23.2 (latest release)
  • onnx: 1.21.0

Suggested Fix

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");
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support