# OpenCV TFLite importer out-of-bounds read in parseTensor This repository contains a proof-of-concept malicious TFLite model that crashes OpenCV's `cv2.dnn.readNetFromTFLite` with an out-of-bounds read at model-load time (SIGSEGV). It is a security PoC for a huntr Model File Format report. The model is intentionally malformed and the repo is gated. Notably, the file is a **structurally valid** TFLite flatbuffer: it passes OpenCV's FlatBuffers verifier, because the verifier checks structure, not the consistency between a tensor's declared shape and its buffer length. ## Affected - `opencv-python` / OpenCV `cv2.dnn`, confirmed on **4.13.0** (latest at time of writing), on Linux. - The vulnerable code is unchanged on `master`. - Entry point: `cv2.dnn.readNetFromTFLite(path)`. ## Root cause `modules/dnn/src/tflite/tflite_importer.cpp`, `TFLiteImporter::parseTensor`. The importer first runs the FlatBuffers verifier (`VerifyModelBuffer`), then for each tensor reads its shape and wraps the tensor's buffer in a `cv::Mat` without validating that the buffer byte size matches the declared element count: ```cpp std::vector shape(tensor.shape()->begin(), tensor.shape()->end()); const Buffer* buffer = model->buffers()->Get(tensor.buffer()); const void* data = buffer->data()->data(); ... Mat res = Mat(shape, dtype, const_cast(data)); // no shape-vs-buffer-size check ``` The verifier only validates flatbuffer structure (offsets/vectors are internally consistent), not that a tensor's declared shape matches its buffer length. A constant tensor whose shape declares far more elements than its buffer holds therefore passes verification, and when the tensor is consumed during layer construction the `Mat` is read/copied over its declared (huge) element count, reading off the end of the small buffer. ## Proof of concept `poc.tflite` is a valid one-Dense-layer model whose weight tensor shape is changed from `[8, 4]` to `[134217728, 4]` while its buffer still holds only 32 floats. The change is a single int32 value inside the shape vector, so the flatbuffer stays structurally valid and the verifier passes. Loading the model makes the importer read ~134M*4 elements from the 32-float buffer. ``` pip install opencv-python # to reproduce (verify.py) python verify.py # loads poc.tflite in a child process; reports the crash # to regenerate poc.tflite from scratch you also need tensorflow: pip install tensorflow && python make_poc.py ``` Observed on opencv-python 4.13.0 (Linux): the child process terminates with SIGSEGV (exit -11) inside `readNetFromTFLite`, before any inference. On Windows it terminates with an access violation (`0xC0000005`). A non-vulnerable build would load the model or reject it cleanly. ## Impact Any application that loads an untrusted or attacker-supplied `.tflite` through OpenCV is exposed. Loading third-party TFLite models is a normal, documented use of this API, and the malicious file passes the importer's own verifier, so a "verify before use" defense does not help. A ~1 KB file reliably crashes the process via an out-of-bounds read in native code (a denial of service), and because the over-read bytes are read into the tensor's Mat, the read can also disclose adjacent process heap memory. ## Fix In `parseTensor`, after reading the shape and buffer, validate that `buffer->data()->size() == shape_product * elemSize` (and reject the model otherwise) before constructing the `Mat`. ## Relation to the other OpenCV importer issues This is a distinct vulnerability from the OpenCV Caffe importer (`caffe_importer.cpp` `blobFromProto`) and ONNX importer (`onnx_graph_simplifier.cpp` `getMatFromTensor`) out-of-bounds issues: a different importer, a different function (`parseTensor` in `tflite_importer.cpp`), and a different model format (TFLite). It is also notable in that the malicious model passes the importer's FlatBuffers verifier.