[KongchangAI]
· 2 min read· 1,320 words

Static Detection of GGUF Parser Overflow Vulnerabilities

Static Detection of GGUF Parser Overflow Vulnerabilities

GGUF parsers repeatedly suffer out-of-bounds from file header integer overflows, which can be statically intercepted before loading.

GGUF, the model container format for mainstream inference frameworks, has no code execution surface, but its hand-written C/C++ parsers repeatedly trigger integer overflows from file header counts, lengths, dimensions, or offsets, escalating into heap out-of-bounds reads and writes. The disclosed CVE cluster spans llama.cpp and PowerInfer, with all trigger values in the file header, enabling static pre-load detection. Author MV2 released gguf-scan, a CVE mapping table, and a malformed header corpus generator. The tool maps to vulnerabilities via rules like GG003, GG004, GG009, and GG011, but has clear boundaries: PowerInfer data offsets are only partially covered, and passing the scan does not guarantee file safety.

Static Detection of GGUF Parser Overflow Vulnerabilities

GGUF is the model container format used by mainstream inference frameworks like llama.cpp, Ollama, and LM Studio. It has no code execution surface of its own—it contains no pickle serialization and no embedded scripts, and opening a file does not "run" anything. The problem lies at the parser layer: hand-written C/C++ ggml reading code and its derivative implementations repeatedly trigger integer overflows from count values, length values, dimension values, or offsets in malformed file headers, ultimately escalating into heap out-of-bounds reads and writes.

Static Detection of GGUF Parser Overflow Vulnerabilities

An Already Public Vulnerability Cluster

These vulnerabilities share a common characteristic: all trigger values are located in the file header. This means a static check before loading can read the file header and flag dangerous signals before the parser ever touches the file.

According to public data compiled by developer MV2 (Munim, Inc.), the currently disclosed related vulnerabilities form a recognizable cluster. Classified by CWE, these vulnerabilities are almost entirely concentrated on out-of-bounds access caused by integer overflows:

  • CVE-2024-21825: Metadata array length overflow in llama.cpp GGUF array/string parsing;
  • CVE-2024-23496: Metadata string length overflow in llama.cpp gguf_fread_str;
  • CVE-2024-23605: Metadata KV count overflow in llama.cpp n_kv handling;
  • CVE-2025-53630: Tensor count (size accumulation) overflow in llama.cpp gguf_init_from_file_impl;
  • CVE-2026-27940: Tensor count overflow in llama.cpp mem_size that bypasses the above 53630 fix;
  • CVE-2026-33298: Tensor dimension overflow in llama.cpp ggml_nbytes();
  • CVE-2026-108955: Tensor data offset overflow in PowerInfer gguf_init_from_file.

The commonality of these vulnerabilities is worth noting: they are not randomly distributed, but repeatedly appear on the same class of code paths—parsing and accumulation calculations of file header fields. In other words, the entire attack surface can be reduced to "integers in the file header."

GGUF File Header Structure Overview: A GGUF file starts with a fixed magic number (0x46554747, i.e., "GGUF"), followed by the version number (uint32), tensor count (uint64), metadata KV pair count (uint64), then a contiguous KV metadata section, followed by the tensor information section (each entry contains name, number of dimensions, length of each dimension, type, data offset), and finally the tensor data section. The entire attack surface is concentrated on these header fields: n_kv, n_tensors, string lengths, dimension array lengths, individual dimension sizes, and tensor offsets—all integers. When the parser performs accumulation, multiplication, or uses these values as allocation/copy lengths, the absence of overflow checks causes incorrect small or negative values to be computed, leading to subsequent buffer access at the wrong size. Understanding this layout explains why a scanner that "only reads the header" can cover this entire class of vulnerabilities.

Design Philosophy of the Static Scanning Tool

Targeting the above patterns, MV2 released a header validation tool called gguf_scan.py (command-line command gguf-scan), licensed under Apache-2.0, depending only on the standard library. Its core design principle: parse only the GGUF file header, never load or execute the model.

Two accompanying materials were also released. gguf_cve_map.json and GGUF_CVE_MAP.md (CC BY 4.0 license) map each advisory to the specific overflowing header field, the corresponding CWE number, and the scanner rule number that can detect the vulnerability. According to the author, this is the first consolidated and reproducible mapping table for this cluster. gguf_cve_corpus.py (Apache-2.0) generates test files containing only malformed file headers.

Integration into CI costs very little, requiring just one line:

gguf-scan ./my-model.gguf --fail-on HIGH

For regression testing your own GGUF parser:

python gguf_cve_corpus.py --out-dir DIR

This command generates a tiny, header-only .gguf file for each row in the mapping table, plus a zero-alignment defense-in-depth test case. Any reader implementing correct bounds checking should reject these files.

How Integer Overflows Escalate into Heap Out-of-Bounds: Taking CWE-190 (Integer Overflow or Wraparound) as an example, parsers commonly use uint64_t total = n * size to accumulate the memory required for tensors. If both n and size come from the file header and their product exceeds UINT64_MAX, the result wraps around to a very small number; the parser allocates a small heap buffer accordingly, then writes n elements, resulting in a heap buffer overflow (CWE-787) or out-of-bounds read (CWE-125). Another common scenario is signed integer overflow: an int-type length field is assigned a value close to INT_MAX, and after adding an offset it becomes negative, bypassing length validation and being passed as size_t to memcpy, again causing out-of-bounds. CWE-787 and CWE-125 are the common classifications for such vulnerabilities, with the root cause being the lack of upfront overflow checks.

Mapping Rules and Actual Coverage

The tool maps one-to-one with vulnerabilities through several rules (GG003, GG004, GG006, GG009, GG011, etc.). For example, GG003 corresponds to tensor count/size accumulation overflows, GG004 to metadata string length overflows, and GG009 to tensor dimension overflows.

You may not have noticed that the PowerInfer case is only partially covered: GG011 can only flag unaligned data offsets, while complete bounds checking of the data region remains a known gap. The author honestly notes this in the documentation, without concealment.

The Meaning of Partial Coverage: "Partial coverage" means the scanner can only detect a certain class of statically determinable conditions, and cannot prove that the corresponding code path is safe at runtime. Taking PowerInfer's gguf_init_from_file as an example, GG011 can flag cases where the data offset is not aligned to the alignment required by the tensor type, thereby indicating potential risk; but whether an out-of-bounds actually occurs also depends on whether the subsequent mmap/fread length calculations match the actual file length. If the offset happens to fall within a legal range but points to the wrong data region, or only goes out of bounds when combined with other fields, static header scanning cannot determine this alone. This explains why the author marks certain CVEs as partially covered, without exaggerating the tool's detection capabilities.

The Tool's Honest Boundaries

The author has a clear self-limitation regarding the tool, and these points are equally important for users:

  • All listed vulnerabilities are already public information, involving no zero-day vulnerabilities, and no new vulnerability details are disclosed;
  • The constructed test files contain only file headers, no tensor data, and no exploit payloads—they merely reproduce the malformed header values;
  • Passing the scan does not mean the file is safe. It only means the file header passed these specific checks; it cannot prove that the file itself or its weights are safe, nor that your loader has no other flaws. Runtime patches still need to be continuously followed up;
  • Coverage is limited to the file header level, and the PowerInfer data offset case is only partially covered.

The value of this tool set is not to "eliminate" all GGUF security risks, but to front-load and intercept a class of repeatedly occurring, precisely modelable vulnerabilities in enterprise or personal model loading pipelines. With model file sources becoming increasingly diverse, this "intercept before load" approach clearly has practical significance.

The code repository and mapping table are available at the munimtechnologies/keras-model-scan project on GitHub.

One-line Summary

GGUF parsers repeatedly suffer out-of-bounds due to file header integer overflows, which can be statically intercepted before loading.

Paragraph Summary

GGUF, the model container format for mainstream inference frameworks, has no code execution surface itself, but its hand-written C/C++ parsers repeatedly trigger integer overflows from count values, lengths, dimensions, or offsets in file headers, ultimately escalating into heap out-of-bounds reads and writes. The disclosed vulnerability cluster covers 7 CVEs in llama.cpp and PowerInfer, with all trigger values located in the file header, making static detection before loading possible. Author MV2 released the gguf-scan tool, a CVE mapping table, and a malformed header test corpus generator, forming a low-cost, reproducible header validation solution. The tool maps to vulnerabilities through rules such as GG003, GG004, GG009, and GG011, but has clear boundaries: PowerInfer data offsets are only partially covered, and passing the scan does not mean the file is safe, so runtime patches still need to be continuously followed up.

#GGUF#integer overflow#static analysis#llama.cpp#PowerInfer#CVE#heap overflow#gguf-scan
Share:

Related articles