Skip to content

Mutation Strategies

Crucible ships 46 structure-aware mutation strategies for the GGUF file format, organized into 6 categories. Each strategy targets a specific structural component to trigger a known class of bugs.

Category weights

The mutator selects categories using weighted random sampling: Metadata (35%), TensorInfo (35%), Header (10%), Consistency (10%), Alignment (5%), Data (5%). Higher weights target sections with the most parser complexity and historical bug density.


Header Strategies

Target the 24-byte fixed header that every GGUF parser reads first.

Strategy Description Bug Pattern
header.version Fuzz version field: 0, 1, 2, UINT32_MAX, random Version handling bugs
header.tensor_count Mismatch count with actual tensor info blocks Buffer overflow on allocation
header.metadata_kv_count Mismatch count with actual KV pairs Over-read past metadata section
header.magic_corrupt Partial magic corruption (keep 1-2 valid bytes) Error path bugs
header.version_mismatch Set version that disagrees with field sizes used Version-dependent parsing bugs

Metadata Strategies

Target the variable-length key-value section. This is the largest attack surface in most GGUF parsers.

Strategy Description Bug Pattern
metadata.key_length Empty keys, 1MB+ keys, embedded null bytes, declared-length mismatches (encoded length != actual key bytes) String handling overflow, parser field desync
metadata.key_content Non-UTF8 sequences, null sleds, path traversal strings, surrogate pairs Encoding bugs
metadata.value_type Invalid enum values (14+, UINT32_MAX), type confusion between similar types Type confusion / wrong getter
metadata.string_value Empty strings, 10MB strings, embedded nulls, non-UTF8 String processing overflow
metadata.array Empty arrays, nested arrays, element type mismatch, large arrays (100K+ elements) Array handling overflow
metadata.int_overflow UINT32_MAX, UINT64_MAX, INT64_MIN in integer fields Integer overflow
metadata.alignment_poison Set general.alignment to 0, 1, 3, 7, UINT32_MAX Division by zero, huge allocation
metadata.key_shadow Duplicate keys like general.architecture with conflicting value types Duplicate key confusion
metadata.add_extra Inject 50-250 extra KV pairs with random types and large values Parser stress / OOM
metadata.invalid_utf8 Inject non-UTF-8 byte sequences in string values Encoding validation bugs
metadata.reorder Randomize the order of metadata key-value pairs Order-dependent parsing bugs
metadata.deep_array Create arrays nested to extreme depth; arrays whose declared element count exceeds actual data (1M declared, 2 emitted) Stack overflow in recursive parsing, read past end of array
metadata.string_truncated Declared string length exceeds actual bytes available (via on-wire length override) Read past end of metadata section

TensorInfo Strategies

Target the per-tensor descriptor blocks that parsers use to locate and allocate tensor data.

Strategy Description Bug Pattern
tensorinfo.n_dims Set dimensions to 0, 5+, UINT32_MAX (spec allows 1-4) Out-of-bounds dimension read
tensorinfo.dim_overflow Set individual dimension values to 0 or UINT64_MAX Allocation size bugs
tensorinfo.type Invalid ggml_type enum values (5, 15, 255, UINT32_MAX) Type lookup crash
tensorinfo.offset Offset beyond file size, UINT64_MAX, overlapping with other tensors Out-of-bounds read
tensorinfo.name Empty names, 1MB names, embedded nulls, non-UTF8, duplicate names String overflow, dedup bugs
tensorinfo.dim_product_overflow Dimension values whose product overflows uint64 Undersized alloc + oversized read/write
tensorinfo.name_collision Give two tensors the same name Deduplication and lookup bugs
tensorinfo.offset_wraparound Offset + size wraps uint64, bypassing bounds checks Out-of-bounds memory access

Alignment Strategies

Target the padding calculations between the metadata section and tensor data.

Strategy Description Bug Pattern
alignment.padding Set alignment to 0, prime numbers, UINT32_MAX, OS page size Padding calculation crash
alignment.extra_padding Insert random non-zero bytes before tensor data section Offset miscalculation
alignment.missing_padding Metadata claims alignment but padding bytes are absent Missing padding handling

Data Strategies

Target the raw tensor data blob at the end of the file.

Strategy Description Bug Pattern
data.truncate Truncate data section mid-tensor Read past end of file
data.overlap Multiple tensors pointing to the same offset Double-read, data confusion
data.zero_length Empty data section with non-zero tensor count Null pointer / zero-size alloc
data.shorter Data section shorter than the sum of all tensor sizes Partial read overflow
data.garbage_fill Fill data section with random bytes Data corruption handling
data.nan_inf Inject NaN and Infinity values into tensor data Special float handling bugs

Consistency Strategies

Violate cross-section invariants that parsers may assume hold true.

Strategy Description Bug Pattern
consistency.tensor_count Header tensor count != actual tensor info block count Over-read / under-read
consistency.metadata_count Header metadata count != actual KV pair count Parser desync
consistency.offset_beyond Tensor offset + tensor data size > total file size Out-of-bounds read
consistency.tensor_size Dimensions claim X bytes but actual data region is Y bytes Size mismatch overflow
consistency.duplicate_offset Multiple tensors claim the same offset range Aliased memory access
consistency.alignment_disagree Metadata alignment value != actual file padding alignment Offset miscalculation

Model-Loader Strategies

Target the model-loading path (llama_model_load) beyond raw GGUF parsing. These strategies mutate architecture keys, hyperparameters, vocabulary fields, and layer counts to trigger integer overflows and assertion failures in the model loading and architecture dispatch code.

Category weighting

Model-loader strategies are registered under the Metadata category for weighting purposes (35% selection probability). They share the metadata budget because they operate on metadata key-value pairs that feed into model initialization.

Strategy Description Bug Pattern
model.architecture Set general.architecture to unknown, empty, or malformed values (null bytes, path traversal strings) Architecture dispatch crash, unhandled enum
model.hyperparam Set hyperparameter keys (embedding_length, head_count, block_count, etc.) to 0, UINT32_MAX, or other boundary values Integer overflow in allocation sizing
model.vocab Mutate tokenizer keys (tokenizer.ggml.model, bos_token_id, eos_token_id) with invalid strings or extreme integer values Tokenizer initialization crash
model.layer_count Set block_count to 0, UINT32_MAX, or values mismatched with actual tensor count Layer iteration overflow, assertion failure
model.tensor_name_schema Corrupt tensor names to break the blk.N.attn_q.weight naming convention parsers rely on Tensor lookup failure, null dereference

Strategy Summary

Category Count Weight Primary Target
Header 5 10% Fixed header fields
Metadata 13 35% Key-value parsing
TensorInfo 8 35% Tensor descriptor blocks
Alignment 3 5% Padding between sections
Data 6 5% Raw tensor data blob
Consistency 6 10% Cross-section invariants
Model-Loader 5 (shared with Metadata) Model initialization path
Total 46 100%

Composability

The mutator may apply multiple strategies in a single pass. Combined mutations (e.g., header.tensor_count + consistency.offset_beyond) often trigger bugs that no single mutation would reach alone.

Header count synchronization

By default, the mutator calls SyncCounts() after all mutations to ensure Header.MetadataKVCount and Header.TensorCount match the actual slice lengths. Strategies that append metadata or tensors (e.g., metadata.add_extra, metadata.key_shadow, tensorinfo.name_collision) automatically get correct header counts. Strategies that intentionally set wrong counts (consistency.tensor_count, consistency.metadata_count, header.tensor_count, header.metadata_kv_count, metadata.string_truncated) opt out of this sync via the CountKeeper interface.