# PoC: stable-diffusion.cpp custom-embedding heap out-of-bounds write (malicious .safetensors) **Target:** `leejet/stable-diffusion.cpp` — `Conditioner::load_embedding` (`src/conditioning/conditioner.hpp:250-253`). **Format:** SafeTensors (`.safetensors`) textual-inversion embedding (also `.pt`/`.ckpt`/`.gguf`). **Class:** CWE-787 heap out-of-bounds write (attacker-controlled length + content), CWE-131 / CWE-682 (incorrect buffer-offset calculation across mixed tensor dtypes). **Verified:** source @ `68f3d6df9f1964e7f942dd242cc9c21b76fa273d`; SIGSEGV reproduced (`CRASH_PROVEN.md`). ## What it is Custom embeddings are accumulated into one shared `std::vector token_embed_custom`, with `num_custom_embeddings` counting the total rows added so far — **both persist across calls**. Each `load_embedding` grows the buffer by `ggml_nbytes(embd)` (this file's dtype) but computes the write offset as `num_custom_embeddings * hidden_size * ggml_type_size(embd->type)` — using **this** file's dtype size for **all** previously-added rows. If an earlier embedding used a smaller dtype (F16, 2 B) and the current one a larger dtype (F32, 4 B), the offset over-counts the earlier rows and the `memcpy` writes past the freshly-resized buffer — an OOB heap write whose size scales with the first embedding's row count (attacker-controlled) and whose bytes are the second embedding's contents. ## Files - `embd_f16.safetensors` — first embedding, dtype F16, shape `[8000, 768]`. - `embd_f32.safetensors` — second embedding, dtype F32, shape `[1, 768]`. - `make_embeddings.py` — regenerates both (`python make_embeddings.py `); `R0` sets the overflow size. - `embd_dtype_oob_repro.cpp` / `embd_dtype_oob_repro` — isolated reproduction of the exact `resize`+`memcpy` arithmetic; SIGSEGVs at `-O0`. - `CRASH_PROVEN.md` — run output + lldb backtrace + the offset math. ## Trigger (real sd.cpp) Place both files in the embeddings dir and reference both tokens in one prompt, e.g. `sd -m model.safetensors --embd-dir . -p "a photo, embd_f16 embd_f32"` — `load_embedding` is called for `embd_f16` (F16) then `embd_f32` (F32); the second call performs the OOB write. Coordinated-disclosure security PoC for the huntr AI/ML bug-bounty program. No payload; it only demonstrates the memory-safety flaw.