YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
ONNX ReferenceEvaluator β Unbounded Shape/Count Memory & Resource Exhaustion (4 operators)
Status: Preparing for Huntr submission
Package: onnx (PyPI) β official Linux Foundation / Microsoft package, onnx.reference.ReferenceEvaluator
Affected files: onnx/reference/ops/op_constant_of_shape.py, op_tile.py, op_expand.py, op_range.py
Class: CWE-789 (Convergent Untrusted-Length Allocation) / CWE-400 (Uncontrolled Resource Consumption), root cause CWE-20 (Improper Input Validation)
Severity: High β models under 220 bytes cause multi-gigabyte memory consumption, either silently succeeding or crashing the process, with no validation opportunity for the caller.
Summary
onnx.reference.ReferenceEvaluator is the pure-Python reference implementation shipped inside the main onnx package (distinct from the separate, compiled onnxruntime engine) β used for testing, CI validation, spec-compliance checking, and lightweight inference without a full runtime.
Four of its operator kernels take a shape / repeat-count / range-length value directly from a graph tensor β in practice, an ordinary tiny Constant node embedded in the model file β and pass it straight into a numpy allocation call with no upper-bound validation:
| Operator | File | Vulnerable call |
|---|---|---|
ConstantOfShape |
op_constant_of_shape.py |
np.full(tuple(data), value) |
Tile |
op_tile.py |
np.tile(x, repeats) |
Expand |
op_expand.py |
np.ones(shape, dtype=data.dtype) * data |
Range |
op_range.py |
np.arange(start, end, step) |
In every case the declaring value is a handful of bytes (a single int64), while the resulting allocation can be gigabytes. None of the four check the requested element count against any bound before calling into numpy.
Proof of Concept
poc_onnx_reference_evaluator_bomb.py builds four minimal, fully valid ONNX models with onnx.helper (no hand-crafted binary patching needed β the vulnerable value is just an ordinary small Constant node) and runs each through ReferenceEvaluator in a subprocess, measuring peak RSS / outcome.
pip install onnx numpy
python poc_onnx_reference_evaluator_bomb.py
Measured results
All four models declare 500,000,000 elements.
| Operator | Model size | Result | Peak RSS / time |
|---|---|---|---|
ConstantOfShape |
165 bytes | silent success, no exception | 1967 MB, 3.5β10.5 s |
Tile |
177 bytes | silent success, no exception | 1967 MB, 0.4 s |
Expand |
167 bytes | crash / OOM-killed | up to 3857 MB before kill |
Range |
215 bytes | crash / OOM-killed | killed |
Two of the four (ConstantOfShape, Tile) return "successfully" with a valid-looking large array and zero error signal β the caller has no way to detect anything went wrong short of monitoring process memory externally. The other two (Expand, Range) crash the process outright. Either way, a file under 220 bytes controls the outcome.
Impact
Any code path that loads and evaluates an untrusted ONNX file through ReferenceEvaluator β CI test harnesses that run community-submitted models, model validation/preview services, lightweight pure-Python inference without onnxruntime β can be forced into multi-gigabyte memory consumption or an outright crash by a file of a few hundred bytes, with the model appearing completely ordinary (it's a normal Constant β operator graph, not a malformed file).
Suggested fix
Before allocating in each of the four kernels, validate the requested element count (product of shape dims for ConstantOfShape/Expand, size(x) Γ prod(repeats) for Tile, (end - start) / step for Range) against a configurable sane maximum, and raise a clear error immediately instead of proceeding to allocate.
Relationship to prior findings
This is the same broad class (CWE-789, CULA) previously confirmed in numpy, joblib, zarr, hickle, skops, anndata, fastparquet, and keras+h5py β but this is the first instance found in ONNX's own reference evaluator, and it's systemic across four separate operator implementations rather than a single code path, discovered by pattern-matching the first confirmed instance (ConstantOfShape) against sibling operators known to have similar historical issues elsewhere in the ONNX ecosystem.
Disclosure
Please do not use this PoC against production systems you do not own or have explicit permission to test.