safetensors-cpp (syoyo) heap-buffer-overflow READ in csafetensors_get_tensor_data PoC

Proof-of-concept for a huntr Model Format Vulnerability report against syoyo/safetensors-cpp - specifically the newer C11 API (csafetensors.c/.h, commit af90b6c, 2025-12-28), not the older C++ header (safetensors.hh).

evil.safetensors is a 75-byte file whose header declares a tensor evil with dtype=F32, shape=[1000000] (needs 4,000,000 real bytes) but data_offsets=[0,4] (only 4 real bytes present in the file).

csafetensors_get_tensor_data() (csafetensors.c:1203-1221) checks ONLY tensor->data_offset_begin > max_size - it does not check data_offset_end and does not compare against shape/dtype, returning a bare pointer with no length. csafetensors_validate() (csafetensors.c:1283-1320) is the ONLY function that actually checks data_offset_end against the buffer size and dtype_size * shape_size against the real byte range - but it is called only from the project's own unit tests, never from csafetensors_load_from_file/csafetensors_load_from_memory.

Verified live (ASan, gcc, fresh clone, same commit as cited above):

$ gcc -fsanitize=address -g -O0 -std=c11 -o poc poc.c csafetensors.c -lm
$ ./poc
==ERROR: AddressSanitizer: heap-buffer-overflow ... READ of size 4
    #0 in main poc.c:43
allocated by thread T0 here:
    #1 in csafetensors_load_from_memory csafetensors.c:1019

Full ASan output in asan_output.txt. poc.c is the exact reproducer compiled and run.

Why this is a meaningfully undertested path (not just a hypothetical)

The project's own fuzzer (fuzzer/fuzz-main.cc) only fuzzes the OLD C++ path (safetensors.hh's safetensors::load_from_memory) - it never exercises csafetensors_* at all. The new C11 API has existed for ~7 months with no fuzzing coverage of its own - exactly the "show us what our scanner doesn't see" class huntr's own guidelines ask for.

Honest limits (disclosed plainly)

This is a heap out-of-bounds READ (CWE-125), not a write primitive - it does not by itself grant code execution. Exploitability depends on whether a downstream consumer skips calling csafetensors_validate() (which exists and correctly catches this exact file in the project's own test suite) - the weakness is that the convenient accessor silently does not carry the one check it needs, not that the library is unsafe by default with no escape hatch. The C11 API is new; no real downstream consumers of csafetensors.c specifically (as opposed to the older safetensors.hh) were identified.

Impact: heap-buffer-overflow read via a crafted .safetensors file with a shape/dtype-vs-data_offsets mismatch, reachable through the standard csafetensors_load_from_memory -> csafetensors_get_tensor_data usage pattern shown in the project's own examples and tests.

Suggested fix: Have csafetensors_get_tensor_data() itself check data_offset_end <= max_size (not just data_offset_begin), and/or call csafetensors_validate() automatically inside csafetensors_load_from_file/csafetensors_load_from_memory rather than leaving it as an easily-skipped separate step.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support