ChristianTeroerde/ovgenai-gguf-q4k-oob-poc overview
PoC: heap out of bounds write in OpenVINO GenAI's GGUF Q4 K dequantizer Security proof of concept for a CWE 787 heap OOB write triggered when openvinotoolkit/o…
Runs locally from ~0.0 MB disk (4 GB VRAM class GPUs with llama.cpp / guIDE).
Repository Files & Downloads
| File | Type | Quantization | Size | Link |
|---|---|---|---|---|
| crafted.gguf | GGUF | GGUF | 0.0 MB | Download |
Model Details
| Model ID | ChristianTeroerde/ovgenai-gguf-q4k-oob-poc |
|---|---|
| Author | ChristianTeroerde |
| Pipeline | — |
| License | mit |
| Base model | — |
| Last modified | 2026-06-18T07:39:27.000Z |
Model README
---
license: mit
tags:
- security-poc
- gguf
- openvino
---
PoC: heap out-of-bounds write in OpenVINO GenAI's GGUF Q4_K dequantizer
Security proof-of-concept for a CWE-787 heap OOB-write triggered when
openvinotoolkit/openvino.genai
loads a crafted .gguf model through its direct-GGUF preview loader.
This repo exists only to reproduce the bug for the maintainer / triager. The
crafted file is a benign 672-byte PoC — it contains no payload; it merely
makes the dequantizer write a few bytes past freshly-allocated heap buffers so
the overrun is observable under valgrind.
Affected
- Component:
openvino.genaidirect-GGUF reader —src/cpp/src/gguf_utils/gguf_quants.cpp
(gguf_load_quantized / extract_q4_k_data). Independent of llama.cpp/ggml.
- Versions:
openvino-genai >= 2025.2.0.0(the GGUF loader's first release), verified at
2025.2.0.0 / 2025.4.0.0 / 2026.2.1.0 and on current master. Not present in <= 2025.1.0.0.
Root cause (one line)
gguf_load_quantized allocates the dequant destination buffers from the tensor's
last dim guarded only by last_dim % 32 == 0 (the Q4_K sub-block size), but
extract_q4_k_data writes a full 256-weight super-block (8 f16 scales + 8 f16
biases + 128 weight-bytes) per 144 input bytes. A tensor with last_dim = 224
(224 % 32 == 0 but 224 % 256 != 0) passes the guard yet overruns scales/biases
by +2 bytes and weights by +16 bytes per affected tensor.
Reproduce
# needs docker (pulls python:3.11, pip-installs the stock wheel, runs under valgrind)
OVGENAI_VER=2026.2.1.0 ./run.sh
run.sh loads crafted.gguf via openvino_genai.LLMPipeline("crafted.gguf", "CPU")
under valgrind --tool=memcheck --error-exitcode=99. Expected:
==…== Invalid write of size 2 … extract_q4_k_data … gguf_load_quantized
==…== Address … is 0 bytes after a block of size 14 alloc'd <-- scales (7 f16), wrote scales[7]
==…== Invalid write of size 8 … unpack_256_4 … extract_q4_k_data
==…== Address … is 0 bytes after a block of size 112 alloc'd <-- weights (28 u32 = 112 B), wrote [112..127]
(docker exits 99 = valgrind found the OOB-writes.) The full captured run is in
valgrind-full.log; a trimmed transcript is in poc-evidence.txt.
Files
crafted.gguf— the 672-byte PoC model (single Q4_K*.weight, declared shape[224], 144 B data + minimal KV).build_gguf.py— regeneratescrafted.gguf(injects the[224]Q4_K tensor past thegguflib's own 256-alignment check).load_crafted.py— the loader called inside the container.run.sh— one-command docker + valgrind reproduction.valgrind-full.log/poc-evidence.txt— captured evidence.
Suggested fix
Guard the super-block size for K-quants (last_dim % 256 == 0 for Q4_K/Q6_K),
or size the destination buffers from n_super_block (the actual write count) rather
than last_dim / weights_per_block.
Run ChristianTeroerde/ovgenai-gguf-q4k-oob-poc with guIDE
Download guIDE — the AI-native code editor with local LLM inference and 69 built-in tools.
Source: Hugging Face · Compare models