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.

Log in or Sign Up to review the conditions and access this model content.

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

Check out the documentation for more information.

OpenCV Caffe importer: ineffective integer-truncated blob size check

This repository contains a proof-of-concept malicious Caffe model that abuses an ineffective size check in OpenCV's cv2.dnn.readNetFromCaffe. A 42-byte file declares a weight blob with roughly 4.3 billion elements while carrying zero bytes of weight data, and the loader accepts it because the length check is performed on a 32-bit-truncated element count.

It is a security PoC for a huntr Model File Format report. The model is intentionally malformed and the repo is gated so it cannot be downloaded casually.

Impact depends on the host allocator (read this first)

The observable result is not identical on every platform, because it depends on whether the host grants or refuses the oversized allocation that the full 64-bit element count implies (about 16 GiB here):

  • On Windows (opencv-python 4.13.0), the allocation is granted via memory overcommit, the subsequent blob copy runs out of bounds, and the process crashes with an access violation (exit code 0xC0000005 / 3221225477). This is a memory-safety crash.
  • On Linux (Debian, opencv-python-headless 4.13.0), the allocator refuses the request and OpenCV raises a catchable cv2.error (Insufficient memory, OutOfMemoryError) inside dstBlob.create(), before any copy. There is no crash on this configuration.

So the honest impact ranges from an uncontrolled memory allocation reachable from a tiny untrusted file (denial of service, catchable on hosts that refuse the allocation) up to an out-of-bounds access and process crash on hosts where the allocation is granted. The underlying defect, the truncated size check, is the same in both cases.

Affected

  • opencv-python / OpenCV cv2.dnn, confirmed on 4.13.0 (latest at time of writing).
  • The same code is present on master.
  • Entry point: cv2.dnn.readNetFromCaffe(prototxt, caffemodel).

Root cause

modules/dnn/src/caffe/caffe_importer.cpp, function blobFromProto:

dstBlob.create((int)shape.size(), &shape[0], CV_32F);
...
// FLOAT raw_data path
CV_Assert(raw_data.size() / 4 == (int)dstBlob.total());
Mat((int)shape.size(), &shape[0], CV_32FC1, (void*)raw_data.c_str()).copyTo(dstBlob);

dstBlob.total() is a 64-bit size_t element count. The assert that is supposed to reject an undersized raw_data buffer casts it to int, truncating the count modulo 2^32. If the BlobShape dims multiply to an exact multiple of 2^32, (int)total becomes 0, so a 0-byte raw_data satisfies 0 / 4 == 0. Each individual dimension still fits in a positive int, so no per-dimension range check fires. The loader then proceeds to allocate and copy a blob whose true 64-bit element count is enormous, which is where the platform-dependent behavior above kicks in.

Files

  • poc.caffemodel - the malicious weights file (42 bytes). One InnerProduct layer with a single weight blob of shape [65536, 65536] (product = 2^32) and zero bytes of raw_data.
  • poc.prototxt - a trivial network that just references the layer. The behavior does not depend on this architecture; any prototxt that causes the blob to be parsed works.
  • make_poc.py - regenerates the two files from scratch (self-contained protobuf encoder).
  • verify.py - loads the model in a child process and reports the exit code (crash vs catchable error).

Reproduce

pip install opencv-python
python make_poc.py        # writes poc.prototxt + poc.caffemodel
python verify.py          # loads in a child process, reports the outcome

Observed:

  • Windows: the child process terminates via access violation (3221225477 = 0xC0000005) during readNetFromCaffe, before any inference.
  • Linux: the child raises a catchable cv2.error (Insufficient memory: Failed to allocate 17179869184 bytes) from dstBlob.create() and exits without a crash.

Fix

Compute and validate the element count in 64-bit and reject blobs whose dimension product overflows, instead of comparing against (int)dstBlob.total(). For example assert raw_data.size() / elemSize == dstBlob.total() using the full size_t value, and bound the total against the actual raw_data size before constructing the source Mat. The same truncation is present on the FLOAT16 path (raw_data.size() / 2 == (int)dstBlob.total()) and should be fixed together.

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