PoC β llama.cpp clip_image_u8::set_pixel 32-bit index overflow β OOB heap write
huntr Model File Vulnerabilities PoC against
ggml-org/llama.cpp @ 2d97363 β tools/mtmd/clip-impl.h.
For authorized security research (responsible disclosure via huntr).
Bug
clip_image_u8::set_pixel/get_pixel (clip-impl.h:485/:477) index the image buffer with 32-bit int:
int idx = (y * nx + x) * 3;. nx = ny = image_size is an mmproj GGUF hparam bounded only to <=65536
(clip.cpp:1179, 1686-1691). set_size allocates with size_t (no overflow, ~2.7 GB for 30000), but the
per-pixel index overflows int for image_size β³ 26756 β negative idx β huge size_t offset β wild
out-of-bounds heap write, reached via the resize loop (mtmd-image.cpp) during preprocessing of any
image with an MLP/LDP/COGVLM/JANUS_PRO/GLM_EDGE/YASA2/GEMMA3 vision head. Distinct from the MiniCPM-V
bucket_coords stack overflow (different file/root cause).
Files
setpixel_repro.cppβ copies the exactclip_image_u8code + resize loop.CRASH_PROVEN.md/gen_and_run.shβ UBSan run showing the signed-integer overflow at the exact line.
Reproduce
c++ -O1 -g -fsanitize=undefined -fno-sanitize-recover=all setpixel_repro.cpp -o setpixel_ubsan
./setpixel_ubsan 30000
# -> setpixel_repro.cpp:29 runtime error: signed integer overflow ... in type 'int' (== clip-impl.h:485)
End-to-end: set clip.vision.image_size = 30000 in a real MiniCPM-less fixed-size mmproj GGUF and run
llama-mtmd-cli --mmproj evil.gguf --image any.png β OOB heap write in the resize/set_pixel loop.
Fix
Index in size_t (size_t idx = ((size_t)y*nx + x)*3;) and/or bound image_sizeΒ²*3 <= INT_MAX.