Skip to content

Resource Exhaustion DoS via Malformed TGA Image #1880

@CyberFrenchie

Description

@CyberFrenchie

i discovered a resource exhaustion denial of service vulnerability in stb_image's TGA parser through fuzzing. A
malformed 19-byte TGA file claiming impossible dimensions causes allocation of 65.5 MB of memory, leading to
application crashes or system resource exhaustion.

  • Type: Denial of Service (Resource Exhaustion)
  • Severity: Medium-High (CVSS 7.5)
  • Attack Vector: Remote (via malicious image file)
  • Affected: All versions of stb_image.h tested (including latest)
  • exploitability: Trivial (just load a crafted TGA file)

Any application using stb_image to load user-supplied images can be remotely crashed.

Proof of Concept

Malicious TGA File** (19 bytes):
Hex: 47 00 0a 0e 00 0a 0a 01 00 01 00 21 f9 04 01 c9 08 00 3b

Claimed dimensions: 1273 x 51457 pixels
Memory allocated: 65,504,761 bytes (62.5 MB)
Amplification: 3,447,619x from 19-byte input

Reproduction:

#define STB_IMAGE_IMPLEMENTATION                                                                                      
#include "stb_image.h"                                                                                                
                                                                                                                      
int main() {                                                                                                          
    int w, h, c;                                                                                                      
    unsigned char *img = stbi_load("dos.tga", &w, &h, &c, 0);                                                         
    if (img) {                                                                                                        
        printf("Allocated: %d bytes\n", w * h * c);                                                                   
        // Output: Allocated: 65504761 bytes (from 19 byte file!)                                                     
        stbi_image_free(img);                                                                                         
    }                                                                                                                 
    return 0;                                                                                                         
}                                                                                                                     
                                                                                                                      
Test Results:                                                                                                         
File size: 19 bytes                                                                                                   
Dimensions: 1273 x 51457 (1 channels)                                                                                 
Memory allocated: 65,504,761 bytes                                                                                    
                                                                                                                      
I can provide the malicious TGA file if needed for testing.                                                           
                                                                                                                      
Root Cause                                                                                                            
                                                                                                                      
The TGA parser does not validate image dimensions before memory allocation:                                           
1. Reads claimed dimensions from header (no validation)                                                               
2. Calculates memory: 1273 × 51457 × 1 = 65,504,761 bytes                                                             
3. Allocates 65.5 MB without checking reasonableness                                                                  
4. No validation that file size matches claimed dimensions                                                            
                                                                                                                      
Suggested Fix                                                                                                         
                                                                                                                      
Add dimension validation before allocation:                                                                           
#define MAX_IMAGE_DIMENSION 65536  // 64K x 64K max                                                                   
                                                                                                                      
// Before allocation:                                                                                                 
if (width > MAX_IMAGE_DIMENSION || height > MAX_IMAGE_DIMENSION) {                                                    
    return stbi__errpuc("image dimensions too large", "Corrupt TGA");                                                 
}                                                                                                                     
                                                                                                                      
// Also check total pixels:                                                                                           
if ((uint64_t)width * (uint64_t)height > (uint64_t)MAX_IMAGE_DIMENSION * MAX_IMAGE_DIMENSION) {                       
    return stbi__errpuc("image too large", "Corrupt TGA");                                                            
}                                                                                                                     
                                                                                                                      
Validate file size consistency:                                                                                       
// File size should roughly match claimed dimensions                                                                  
size_t expected_min_size = ((size_t)width * (size_t)height) / 10;  // Account for compression                         
if (input_size < expected_min_size) {                                                                                 
    return stbi__errpuc("file size inconsistent with dimensions", "Corrupt TGA");                                     
}                                                                                                                     
                                                                                                                      
Discovery Method                                                                                                      
                                                                                                                      
Found via AFL++ fuzzing campaign:                                                                                     
- Fuzzer: AFL++ v4.35c with AddressSanitizer                                                                          
- Runtime: 22 hours                                                                                                   
- Executions: 314 million test cases                                                                                  
- Found: 17 timeout cases (this is the first analyzed)                                                                
                                                                                                                      
Additional Information                                                                                                
                                                                                                                      
I'm happy to:                                                                                                         
1. Provide the 19-byte malicious TGA file for testing                                                                 
2. Share full technical analysis                                                                                      
3. Help test proposed fixes                                                                                           
4. Analyze the other 16 timeout cases found during fuzzing

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