By UNST33R

llama.cpp CVE-2026-116096: the mmproj file is part of your attack surface

An out-of-bounds write in llama.cpp's Pocket-TTS component, triggered by a malicious mmproj file, with a public exploit. Timeline, auxiliary-file attack surface table, local verification script, and what red-team operators should check.

A new llama.cpp vulnerability published as CVE-2026-116096 underscores an operational fact for anyone running open-weight models locally: a downloaded model directory contains multiple binary and structured artifacts that the C++ runtime parses at startup with full process privileges. The bug surfaced on r/LocalLLaMA on October 26 (PSA thread, 73 upvotes within hours) and entered our monitoring queue the same morning.

What the CVE says

Per the NVD entry, the vulnerable function is list_pockettts_state_slots in tools/mtmd/models/pockettts-gen.cpp, part of the Pocket-TTS multimodal/audio component of ggml-org/llama.cpp. Passing a crafted mmproj (multimodal projector) file triggers an out-of-bounds write during slot enumeration. A proof-of-concept exploit is already public, and the trigger path requires only local file loading: pass the runtime a malicious projector file and memory corruption occurs inside your local inference process.

FieldDetail
IdentifierCVE-2026-116096
Componentggml-org/llama.cpp — Pocket-TTS (tools/mtmd/models/pockettts-gen.cpp)
Vulnerable functionlist_pockettts_state_slots
Bug classOut-of-bounds write via crafted --mmproj input file
Mitigation on masterBuilds around b11871 abort via GGML_ASSERT on the malformed state-slot path
Root-cause fixPull request #29360 bounds-checks the slot index before writing

The timeline as tracked

Reconstructed from the NVD record, repository history, and the community PSA thread:

  1. NVD publication: the advisory lands with file- and function-level detail (tools/mtmd/models/pockettts-gen.cpp, list_pockettts_state_slots) and notes that a public exploit exists.
  2. r/LocalLLaMA PSA (October 26): the warning thread highlights that mmproj files ship alongside popular multimodal GGUF quantizations and rarely get hashed or audited separately.
  3. Assert mitigation on master: recent builds (around b11871) convert the out-of-bounds path into a hard GGML_ASSERT abort, turning silent memory corruption into a deterministic crash. Users on older binaries remain exposed to arbitrary out-of-bounds writes.
  4. Root-cause bounds fix: pull request #29360 addresses the underlying write in list_pockettts_state_slots. Distro-packaged binaries, Homebrew bottles, and pinned Docker base images lag upstream master until rebuilt.

The practical triage takeaway: exposure depends on both your llama.cpp build revision and whether your workflow passes third-party --mmproj files to llama-mtmd-cli, llama-server, or wrapper tools that bundle libmtmd.

Why mmproj sits inside the trust boundary

A multimodal or speech-capable model directory typically contains a primary .gguf weights file plus an mmproj-*.gguf projector file that maps visual or audio embeddings into the language model's token space. At startup, the loader parses tensor headers, metadata key-value pairs, and state-slot tables from both files inside the same OS process.

Teams carefully choose, benchmark, and compare the primary .gguf weights, while the accompanying projector file rides along unexamined from whichever quantization mirror happened to bundle it. Every auxiliary artifact in a model directory shares that same privilege boundary:

Artifact in model directoryTypical filenameWhat parses itFailure mode when untrusted
Primary model weightsmodel-Q4_K_M.ggufgguf_init_from_file / tensor loaderMalformed tensor offsets or metadata integer overflows
Multimodal projectormmproj-model-f16.ggufmtmd / pockettts-gen.cpp (--mmproj)Out-of-bounds write in projector slot setup (CVE-2026-116096)
GBNF grammar constraintsjson_tool.gbnfllama_grammar_init (--grammar-file)Parser recursion exhaustion or state-table corruption
Jinja chat templatestokenizer_config.json / embedded GGUF KVTemplate engine (--chat-template-file)Silent prompt/tool-call macro injection into agent turns

The threat-model debate, both sides

The top-voted comment in the PSA thread (80+ upvotes) dismissed local file triggers as a non-issue on the grounds that running untrusted model files locally already hands control to the uploader. A sharper counter-argument in the thread pointed out the operational reality: local LLM workflows routinely download multi-file repositories from community mirrors (especially during the October Hugging Face takedown wave), and operators treat GGUF directories as passive data rather than executables.

Both perspectives capture part of the truth. Treat every file passed to a C/C++ tensor parser as untrusted binary input. When an operator verifies the SHA-256 of the main 20 GB .gguf against an upstream release table and grabs mmproj-f16.gguf from an unverified community re-upload, the unverified sidecar file becomes the easiest path into the workstation.

Model file supply chains, again

This vulnerability follows the same structural pattern as the LiteLLM 1.107.0 backdoor incident and the broader abliterated ecosystem supply analysis: in open-weight tooling, auxiliary artifacts between you and the base weights receive scrutiny proportional to their visibility rather than their OS privileges. Because mmproj sidecars attract almost no manual review, parser bugs in multimodal loaders carry low detection risk for an attacker.

Verification script and checklist for local runs

Before loading a downloaded model directory with llama-server or llama-mtmd-cli, lock down the binary version and record a full-directory manifest:

# 1. Check your llama.cpp build number (ensure >= b11871 or patched with PR #29360)
llama-server --version

# 2. Hash EVERY artifact in the model directory, including mmproj and grammars
find ./model-dir -type f \( -name "*.gguf" -o -name "*.gbnf" -o -name "*.json" \) \
  -exec shasum -a 256 {} + | sort -k 2 > ./model-dir/SHA256SUMS.manifest

# 3. Verify manifest before launching inside an unprivileged container without host-home mounts
shasum -a 256 -c ./model-dir/SHA256SUMS.manifest && \
docker run --rm --network none --read-only \
  -v "$(pwd)/model-dir:/models:ro" \
  ghcr.io/ggml-org/llama.cpp:server \
  -m /models/model-Q4_K_M.gguf --mmproj /models/mmproj-f16.gguf

Checklist for local lab environments:

  • Fetch model directories from one canonical source and log the exact commit SHA of the Hugging Face or mirror repo.
  • Hash every file in the directory (.gguf, mmproj, .gbnf, .json) into a versioned manifest.
  • Run first-time loads inside a network-isolated container or disposable VM with read-only mounts.
  • Pin your llama.cpp build revision and rebuild once PR #29360 is merged into your release track.
  • Strip --mmproj flags from launch scripts whenever a workload only requires text completion.

Assessing someone else's local LLM deployment

If you red-team internal LLM deployments for clients, CVE-2026-116096 provides a concrete audit check. Ask the engineering team for their model artifact manifest and inspect three areas:

  • The hash gap: teams frequently record SHA-256 digests for the primary .gguf weights while leaving mmproj, grammar, and template sidecars unhashed.
  • The provenance gap: auxiliary projector files are often copied from secondary quantization repos when the primary uploader omits them, mixing trust domains inside one directory.
  • The sandbox gap: developers test new multimodal checkpoints directly on corporate laptops holding SSH keys, cloud credentials, and engagement notes.

Each gap maps directly to a remediation item: enforce whole-directory manifest verification and isolate the C++ model loader from workstation credentials.

FAQ

Am I affected if I only run pure-text GGUF models? The vulnerable list_pockettts_state_slots path sits in the Pocket-TTS multimodal/audio component (tools/mtmd), so direct exposure requires loading an mmproj file. The broader control still applies: any file parsed by gguf_init_from_file or llama_grammar_init exercises C/C++ parsing code on your host.

Should I pull llama.cpp from master right now? Track the merge of PR #29360 for the bounds-checked fix, and ensure any interim build is at least at the b11871 GGML_ASSERT milestone while running inside a container sandbox.

Where a hosted endpoint changes the surface

Calling open-weight models through an OpenAI-compatible API removes local GGUF and mmproj binary parsing from operator workstations: your harness sends HTTPS JSON requests to https://api.unst33r.si/v1, and the inference provider owns artifact verification and container isolation. Teams that combine local R&D labs with hosted red-team harnesses should enforce the manifest checklist above on local GPUs and route automated agent sweeps through fixed hosted tiers (unst33r-flash, unst33r-deepseek, and unst33r-pro). Review our model catalog, per-token pricing, and acceptable-use policy for hosted deployment details.