Six llama.cpp CVE records were published in a thirteen-minute window on 6 August 2026, and not one of them contains a fixed-version field of any kind, although CVE-2026-43630 does link an upstream patch commit. The build numbers quoted as the ceiling, b9058 and b9060, were both cut on the afternoon of 7 May 2026, three months before those advisories, so they are the highest builds someone tested rather than fix boundaries: the last build released on or before 11 September 2026 is b10917, which sits 1857 build numbers above b9060. The ceilings also differ per CVE, with three capping at b9058, one at b7653, and two reading b7492 through b9060. Four of the six are gated on a switch that ships off, two on the slot save directory and two on the idle-sleep option. None of the thirteen published GitHub security advisories on the repository corresponds to this batch, although the project clearly does run a disclosure process, with b3561, b8146 and b8492 all named as patched builds for earlier bugs. The separate RPC backend is where the real fix history lives, and the project's own README tells you never to run it on an open network or in a sensitive environment, with a documented default endpoint of 127.0.0.1:50052 and no authentication, TLS or allowlist documented anywhere in that file. Start by answering one question about your own binary: was it built with -DGGML_RPC=ON, and is anything listening on 50052.
Six CVE records for llama.cpp were published in a thirteen-minute window on 6 August 2026, between 15:40 and 15:53 UTC. Every one names an affected build range. None contains a fixed-version field of any kind. If your llama.cpp server security hardening starts by reading an affected range and picking the next build up, this batch hands you nothing to pick.
b9058 caps three of the six records, and it is older than it looks. Build tag b9058 was published on 7 May 2026 at 15:39 UTC and b9060 at 18:35 UTC the same afternoon, three months before the advisories that cite them. The last build released on or before the date on this post is b10917, published 11 September 2026, and it sits 1857 build numbers above b9060. A ceiling in these records is the highest build somebody tested, not the last build that contains the bug.
So this is not a patch-to-version guide. There is no version to patch to, and that changes what hardening means here.
A build tag is a timestamp, and b9058 is three months older than the advisory
llama.cpp cuts a numbered build release per merge rather than on a release cadence. Eight separate build releases carry an 11 September 2026 timestamp. The number goes up because time passed, not because an interface changed, so none of the habits that come with semantic versioning transfer: no patch line, no backport branch, and no signal in the number itself about what a build contains.
That matters in two directions. Reading b9058 as a floor tells a reader on b10917 they are clear, when nothing in the record supports that. Reading it as a precise ceiling is wrong too, because the six do not share one: CVE-2026-43627, CVE-2026-43628 and CVE-2026-43629 cap at b9058, CVE-2026-43630 caps at b7653, and CVE-2026-43631 and CVE-2026-43632 both read b7492 through the latest b9060.
Two further details make these ranges hard to act on. Three of the six carry a semantic version range alongside the build range, running from 0.4.0, 0.11.0 or 0.16.1 up to 0.17.1, and CVE-2026-43630 carries a bare 0.17.1 with no range at all, so a scanner keyed on one numbering and a deployment pinned to the other will not agree. And one ceiling is not pinnable at all: b7653, the cap on CVE-2026-43630, exists as a git tag at commit 193ee38a but has no release artifact, while b7651, b7652, b7654 and b7655 all carry releases dated 6 and 7 January 2026.
Six advisories in thirteen minutes, and no fixed build in any of them
Each of the six was scored under both CVSS 4.0 and CVSS 3.1, and the two disagree in every case: 9.2 against 8.1, 8.5 against 7.8, 6.3 against 6.5. A bare severity with no version label attached is not a fact about these CVEs.
Four of the six carry AV:N, network attack vector: CVE-2026-43629, CVE-2026-43630, CVE-2026-43631 and CVE-2026-43632. Each of those four names a precondition in its own description that is off in a default llama-server. Two need write access to the slot save directory, which the server does not create unless --slot-save-path is given, documented as default disabled. Two need --sleep-idle-seconds, documented as default -1, meaning disabled. The other two, CVE-2026-43627 and CVE-2026-43628, are scored AV:L in both CVSS versions.
CVE-2026-43628 will not resolve cleanly. Its description names an unauthenticated crafted HTTP request to the completions endpoints; its own vectors say local access with user interaction required. A score and an impact description pointing in different directions is the mode of analysis we worked through in the NVIDIA Triton version floor analysis. Treat it as reachable from a request body until you have read the DRY sampler at your own pinned tag.
The earlier llama.cpp advisories do name a remediation:
Seven identifiers, seven named remediations, and the metadata still does not line up. One of the seven points at a commit SHA rather than a build tag, and a separate advisory for an out-of-bounds write in llama-server uses SHAs on both ends: vulnerable at or below 55d4206c8, patched at or above c78fb90. CVE-2026-33298 records a range below b7437 and a patched build of b7824, so its range and its remediation do not meet. Pin a build and verify it yourself rather than trusting a scanner's version range.
The project's advisory database holds thirteen published advisories and none corresponds to CVE-2026-43627 through CVE-2026-43632. Those six were assigned by a third-party CNA rather than through the project's own process. Five of them carry exactly two references, an advisory page and a public patch repository maintained by the researcher who reported them. That repository's README states the advisories were closed without fixes or CVE assignment and that a June 2026 patch pull request was closed without merging. Read that as the reporter's account. What is independently established is narrower: no upstream advisory exists for any of the six. The same repository names a seventh identifier, CVE-2026-43626, which has no published CVE record, so six are citable rather than seven.
CVE-2026-43630 is the exception. Its record carries four references rather than two, one tagged as a patch and pointing at upstream commit f93c09e, memory : fix seq_id bounds in llama_memory_recurrent::state_read_meta(), committed 23 March 2026. One of the six does have an upstream fix, in a commit rather than a named build, and it lands more than two months after b7653, the ceiling that same record states, so the builds in between fall outside the stated range while still predating the fix.
| CVE (all published 2026-08-06) | What breaks | Affected builds | CVSS 4.0 / 3.1 | Precondition in the record | Fixed build |
|---|---|---|---|---|---|
| CVE-2026-43627 | Integer overflow in llama_batch_init(); unchecked multiplications in malloc() wrap past INT32_MAX | b1283 to b9058 | 8.5 high / 7.8 high | Crafted parameters; AV:L in both vectors | None in the record |
| CVE-2026-43628 | Integer underflow and out-of-bounds read in the DRY sampler via dry_allowed_length set to INT32_MIN | b3978 to b9058 | 8.5 high / 7.8 high | Description names unauthenticated /v1/completions and /v1/chat/completions; vectors are AV:L with UI:P and UI:R | None in the record |
| CVE-2026-43629 | Heap buffer overflow in the KV cache state restore path; state_read_data() computes a write size without overflow checking | b4882 to b9058 | 9.2 critical / 8.1 high | Write access to the slot save directory | None in the record |
| CVE-2026-43630 | Out-of-bounds read in the recurrent memory state restore path; an oversized seq_id leaks heap pointers into the server log | b5702 to b7653 | 6.3 medium / 6.5 medium | Write access to the slot save directory | No build named; record links a patch commit |
| CVE-2026-43631 | Use-after-free on the vocab pointer in llama-server | b7492 to b9060 | 9.2 critical / 8.1 high | --sleep-idle-seconds enabled | None in the record |
| CVE-2026-43632 | Use-after-free in six tokenization endpoints that bypass the task queue and touch ctx_server.vocab on HTTP worker threads | b7492 to b9060 | 9.2 critical / 8.1 high | --sleep-idle-seconds configured | None in the record |
| CVE | Component | Vulnerable range as recorded | Remediation named | Score |
|---|---|---|---|---|
| CVE-2024-42477 | ggml_type_size, RPC path | < b3561 | >= b3561 | 5.3 medium in the project advisory |
| CVE-2024-42478 | rpc_server::get_tensor, arbitrary address read | < b3561 | >= b3561 | 5.3 medium in the project advisory |
| CVE-2024-42479 | rpc_server::set_tensor, write-what-where via the unsafe data pointer | < b3561 | >= b3561 | 10.0 critical in the CNA record, 9.8 in the project advisory, both CVSS 3.1 |
| CVE-2025-53630 | gguf_init_from_file_impl, integer overflow to heap out-of-bounds read and write | < 26a48ad699d50b6268900062661bd22f3e792579 | that commit, dated 2025-07-09 | 8.9 high, CVSS 4.0 |
| CVE-2026-27940 | mem_size integer overflow in gguf.cpp, an explicit bypass of the CVE-2025-53630 fix | <= b8145 | >= b8146 | 7.8 high, CVSS 3.1 |
| CVE-2026-33298 | GGUF tensor parsing, heap buffer overflow via integer overflow | < b7437 | b7824 | 7.8 high in the project advisory |
| CVE-2026-34159 | RPC backend deserialize_tensor(), unauthenticated remote code execution | Prior to b8492 in the CNA record, <= b7991 in the project advisory | b8492 | 9.8 critical, CVSS 3.1 |
The one construct you can still read at b10917
CVE-2026-43627 can be checked by reading the tree today. It describes unchecked multiplications inside malloc() calls in llama_batch_init(). Here is that function in full, in src/llama-batch.cpp at tag b10917, the build published on 11 September 2026:
struct llama_batch llama_batch_init(int32_t n_tokens_alloc, int32_t embd, int32_t n_seq_max) {
llama_batch batch = {
/*n_tokens =*/ 0,
/*tokens =*/ nullptr,
/*embd =*/ nullptr,
/*pos =*/ nullptr,
/*n_seq_id =*/ nullptr,
/*seq_id =*/ nullptr,
/*logits =*/ nullptr,
};
if (embd) {
batch.embd = (float *) malloc(sizeof(float) * n_tokens_alloc * embd);
} else {
batch.token = (llama_token *) malloc(sizeof(llama_token) * n_tokens_alloc);
}
batch.pos = (llama_pos *) malloc(sizeof(llama_pos) * n_tokens_alloc);
batch.n_seq_id = (int32_t *) malloc(sizeof(int32_t) * n_tokens_alloc);
batch.seq_id = (llama_seq_id **) malloc(sizeof(llama_seq_id *) * (n_tokens_alloc + 1));
for (int i = 0; i < n_tokens_alloc; ++i) {
batch.seq_id[i] = (llama_seq_id *) malloc(sizeof(llama_seq_id) * n_seq_max);
}
batch.seq_id[n_tokens_alloc] = nullptr;
batch.logits = (int8_t *) malloc(sizeof(int8_t) * n_tokens_alloc);
return batch;
}No bounds or overflow check runs on n_tokens_alloc, embd or n_seq_max before any of those multiplications, and no malloc return is checked for NULL. That is the construct the CVE describes, present 1859 build numbers above the b9058 ceiling in that advisory.
One function, one tag. It establishes nothing about the other five, which were not read at source level here.
The point is the procedure, not the verdict. Because no advisory names a fixed build, the only way to know your own status is to check out your pinned tag and open the file each description names: src/llama-batch.cpp for CVE-2026-43627, the DRY sampler in the sampling source for CVE-2026-43628, the KV cache state_read_data() path for CVE-2026-43629, and, for the last two, the vocab lifetime around the sleep path in tools/server. Look for a bounds check. CVE-2026-43630 is the one you can settle faster: check whether your build contains the commit its record links. That is the work an advisory would normally have done for you.
The RPC backend has a real fix history and a README that tells you not to run it
llama.cpp ships a second server binary, ggml-rpc-server, which lets one host borrow accelerators on another. It is separate from llama-server, it is not part of a default build, and its README opens with this, verbatim:
This example and the RPC backend are currently in a proof-of-concept development stage. As such, the functionality is fragile and insecure. Never run the RPC server on an open network or in a sensitive environment!
Read that file end to end and it documents no authentication, no TLS, no allowlist and no credential of any kind. The switches it shows are -p for the port, --device for accelerator selection and -c for the local cache, plus the environment variables CUDA_VISIBLE_DEVICES, LLAMA_CACHE, GGML_RPC_NO_RDMA and GGML_RPC_DEBUG. Nothing is configurable, so the security posture of the RPC transport is the network it sits on.
$ bin/ggml-rpc-server # ... CUDA init lines omitted ... Starting RPC server v3.0.0 endpoint : 127.0.0.1:50052 local cache : n/a # ... a Devices: line per exposed accelerator follows ... # Selecting devices and port, both documented forms: $ CUDA_VISIBLE_DEVICES=0 bin/ggml-rpc-server -p 50052 $ bin/ggml-rpc-server --device CUDA0 -p 50052 # How the main host consumes it: $ llama-cli -hf ggml-org/gemma-3-1b-it-GGUF -ngl 99 --rpc 192.168.88.10:50052,192.168.88.11:50052
The banner prints 127.0.0.1, so a 50052 reachable from another machine is something a deployment did on purpose. The server exposes every accelerator on the host by default, or a single CPU device if there are none.
This is where the fix history lives. Three RPC advisories landed on the same day in August 2024, all fixed in b3561. Then CVE-2026-34159: deserialize_tensor() skipped all bounds validation when a tensor's buffer field was 0, so crafted GRAPH_COMPUTE messages read and wrote arbitrary process memory, and pointer leaks from ALLOC_BUFFER and BUFFER_GET_BASE completed an ASLR bypass. Its record states that no authentication is required, just TCP access to the port. It is patched in b8492, whose release commit is the fix itself, titled rpc : RCE patch, dated 23 March 2026.
The two primary sources disagree about that floor. The CNA record says the issue is patched in b8492. The project's own advisory for the same CVE records a vulnerable range of at or below b7991 and leaves its patched field empty. b8492 is the first safe build, because its release points at the fix commit; b7991 is not a floor.
For an on-premise estate this is the paragraph that changes the answer. The README says never run it on an open network or in a sensitive environment, and a regulated internal network is a sensitive environment by definition. Multi-host GPU pooling across an internal VLAN is exactly the deployment that warning covers. The transport has no credential, so the blast radius is every host that can route to the port, including a compromised workstation on the same segment. What to put in front of a server that has no identity of its own is argued in securing an Ollama server exposed to the internet.
The first question is whether the transport is compiled into your binary at all. It is opt-in at build time on both ends, added with -DGGML_RPC=ON, so a stock build does not link it.
# First-pass indicator only. The authoritative answer is your own cmake invocation, # or the build metadata your vendor publishes for the bundle you installed. strings "$(command -v llama-server)" | grep -c 'GGML_RPC\|ggml-rpc' || true # What is actually listening. 8080 is the documented llama-server --port default; # 50052 is the ggml-rpc-server banner default. ss -ltnp | grep -E ':(8080|50052)\b'
If the symbol is absent, the RPC attack surface does not exist in that binary, and CVE-2026-34159 and the 2024 trio become inventory questions rather than exposure.
Slot save and restore turns a directory on disk into a parse input
--slot-save-path PATH is documented as default disabled. Setting it does two things at once: it gives the server somewhere to write prompt cache state, and somewhere to read it back from, at sizes the file itself declares. What slot save and restore is for, and the cache mechanics around it, we covered in prompt reprocessing on sliding window and hybrid models. Here it matters only as the switch that creates a parse target.
Both CVEs in that path name the same precondition: write access to the slot save directory. In CVE-2026-43629, state_read_data() computes a write size without overflow checking, so a state file whose cell_count multiplication wraps or exceeds the tensor buffer allocation writes attacker-controlled bytes past the boundary. CVE-2026-43630 is the quieter one: an oversized seq_id in the recurrent memory state restore reads past the end of the cells array and leaks heap data, including pointer values, into the server logs.
So the control question is the directory, not the flag. Who can write there: the server's own uid, any other process on the box, any container that mounts the same volume, the backup and restore jobs, and every operator with shell on the host. Give it the controls the model directory gets: it is an input the server parses at sizes it takes from the file.
The leak destination in CVE-2026-43630 matters separately for regulated deployments. Heap pointers in the server log means the log shipper, the retention policy and the SIEM are carrying process memory addresses off the inference host. If those logs leave the perimeter for a managed observability service, those addresses leave with them.
The documented endpoints are POST /slots/{id_slot}?action=save, ?action=restore and ?action=erase. If the slot save path is set and those endpoints are reachable, the write side of the precondition is reachable over HTTP too, not just from the filesystem.
The GGUF file is parser input, and one Jinja CVE belongs to a different package
--jinja is documented as default enabled, so the chat template baked into a GGUF file is parsed by the server on every request that renders a conversation. Whether a model file is malicious at intake is a different problem, covered in why a clean picklescan report is a blocklist result rather than proof. The question here is narrower: does the loader survive a malformed file.
It has a documented history of not surviving one. CVE-2025-53630 was an integer overflow in gguf_init_from_file_impl() in ggml/src/gguf.cpp leading to a heap out-of-bounds read and write, fixed by a commit dated 9 July 2025. Eight months later CVE-2026-27940 documented a bypass of that fix in the same file: the same overflow class in the mem_size calculation, an undersized heap allocation, and a subsequent fread() writing 528 or more bytes of attacker-controlled data past the boundary. Its own title says the earlier fix overlooked some areas. It is fixed in b8146.
CVE-2024-34359 is against llama-cpp-python, the separate Python package, not the C++ server: its Llama constructor loaded the chat template out of GGUF metadata and parsed it with a sandbox-less Jinja2 environment, scored 9.7 critical on CVSS 3.1, affecting v0.2.30 through v0.2.71 and patched in v0.2.72. If you run llama-server, that record is not about your binary. The one that is, CVE-2026-18581, is a reachable assertion in the minja template parser triggered by the input {{9|9|{, scored 3.3 low on CVSS 3.1 with a local attack vector and pinned to a commit prefix rather than a build range. Take it as evidence that the parser is reachable input, not as a headline.
Turning it off is a documented flag. At b10917 the server README spells that row --jinja, --no-jinja, default enabled, so a deployment that serves completions rather than chat can pass --no-jinja and take the template engine out of the request path. Confirm it with llama-server --help on your own pinned tag. Why a chat template is a policy artifact rather than a formatting detail is argued in the Ollama exposure write-up.
What --api-key, --host and --no-webui cover, and the listener they cannot reach
From the shipped README: --host defaults to 127.0.0.1, and binds a UNIX socket instead if the address ends in .sock. --port defaults to 8080. --api-key takes a comma-separated list and defaults to none; --api-key-file reads one key per line and treats lines starting with a hash as comments. The web UI is on by default and off with --no-webui. --props ships disabled, --slots enabled.
llama-server \ --model /srv/models/model.gguf \ --host 127.0.0.1 \ --port 8080 \ --api-key-file /etc/llama.cpp/api-keys \ --no-webui # Left unset on purpose, because each is a stated precondition in the August 2026 batch: # --slot-save-path PATH (default: disabled) -> CVE-2026-43629, CVE-2026-43630 # --sleep-idle-seconds SEC (default: -1) -> CVE-2026-43631, CVE-2026-43632
The .sock behaviour on --host is worth a second look. On a single-host deployment where the only client is a gateway on the same machine, binding a UNIX socket removes the TCP listener entirely and filesystem permissions become the access control.
What --api-key gates is a question about your build, not a fact to assume. Probe the six handlers named in CVE-2026-43632 first, since that CVE exists because they bypass the task queue and touch the vocab pointer on HTTP worker threads. One of the six is documented under a different path at b10917 than the CVE record spells it, and a second appears there only as an alias, which is its own argument for probing rather than assuming:
# From a host that is not the server, presenting no credential.
# Paths as documented in tools/server/README.md at b10917. The record's /rerank is
# listed there as an alias of /reranking; its /anthropic/count_tokens is documented
# as /v1/messages/count_tokens. Check both against --help on your own build.
# 401 means the key is enforced on that path. Anything else is the answer you needed.
for p in /tokenize /detokenize /infill /apply-template /reranking /v1/messages/count_tokens; do
curl -s -o /dev/null -w "$p %{http_code}\n" -X POST "http://llm.internal:8080$p"
doneThe gap none of these flags closes is the other listener. ggml-rpc-server has no key, no TLS and no allowlist, so every control in this section stops at the llama-server process. A deployment that hardened 8080 and left 50052 open on the same host hardened the endpoint an attacker does not need. Controls that look enforced and are not are covered for vLLM in the CVE-2026-22778 hardening review and for cluster runtimes in Ray token authentication.
The gate: pin a build, cut the surface at compile time, write down the acceptance
Pinning is the first move:
git clone https://github.com/ggml-org/llama.cpp cd llama.cpp git checkout b10917 # a build tag is a point in time, not a semantic version cmake -B build # RPC is NOT built unless you add -DGGML_RPC=ON cmake --build build --config Release # Record what you shipped, next to the model hash, in the change record: git rev-parse HEAD
b10917 appears here as a worked example of pinning, the last build tag published on or before the date on this post. It is not a security floor, and no build number is.
Compile-time surface reduction is the move that holds in a regulated estate. If the deployment does not pool GPUs across hosts, do not pass -DGGML_RPC=ON. If it does pool, the compensating controls have to be network ones: a dedicated segment, no route from user-facing subnets, and the port closed on every host that is not a pooling peer.
For the records with no fix, four things are available, and they are not exclusive. Unset --slot-save-path and --sleep-idle-seconds unless a named operational requirement needs them, which removes the stated precondition for four of the six. Read the code paths named in the six descriptions at your pinned tag and record what you found. Decide about the third-party patches on their merits: the reporting researcher publishes per-CVE patch files applied with git apply, or all at once with git apply --3way, and what you take on is unreviewed changes to a C++ memory-management path, with no upstream review and no patch file for the one already fixed upstream. We are not recommending them. And write a risk acceptance naming the identifiers you could not close, the pinned build tag, the preconditions you removed, and a date to re-check for an upstream fix.
Bundled runners need the same discipline. Desktop apps, container images and commercial bundles carry a llama.cpp runner inside them, and the question for the supplier, per release, is which build number it contains and whether its entrypoint sets either of those two flags by default. Nothing here checked any downstream bundle, and no vendor should be assumed affected or clear.
Three things this week. Run the listener check on every inference host; if anything outside loopback answers on 50052, close it today rather than scheduling it. Grep your systemd units, container entrypoints and bundled runners for --slot-save-path and --sleep-idle-seconds, and unset both unless something named depends on them. Then write the pinned build tag and its commit SHA into the change record beside the model file hash, with the cmake options you used and a re-check date. For the rest of the control set around self-hosted inference, start at our AI security pillar.
FAQ
Quick answers to the questions this post tends to raise.


