Skip to content

OOB read in the GGUF loader: tensor data offset and size are not bounded against the file mapping #4136

Description

@professor-moody

Loading a crafted GGUF file makes the loader read outside the mapped file. Filing this publicly as a robustness issue, as suggested when the advisory was closed.

The vendored gguflib builds a tensor's data pointer from fields read straight out of the file. In gguf_get_tensor():

tensor->offset = ctx->data_off + *offset;
tensor->weights_data = ctx->data + tensor->offset;

*offset and bsize come from the file and are never checked against ctx->size. A crafted tensor places weights_data outside the mapping, and any later read of bsize bytes reads out of bounds. MLX reaches this through extract_tensor_data.

Control versus crafted under AddressSanitizer, only the offset field differs:

  • offset 0: loads normally, exits clean
  • offset 1<<40: SEGV inside __asan_memcpy on the tensor read

Re-checked on main on 2026-07-17, after #3436 force-enabled the gguflib asserts in release builds. Those asserts cover the metadata and tensor-info walk. They do not cover the data region.

Related but not the same: CVE-2025-62609 added a weights_data == nullptr check in load_gguf(). That does not catch a non-null pointer landing outside the mapping.

Upstream, antirez/gguf-tools#33 proposes the bound, checking offset plus size against the mapping. An earlier PR there, #28, bounded the metadata walk only.

Happy to share the crafted file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions