An out-of-bounds read vulnerability exists in png_image_read_composite when processing palette images with PNG_FLAG_OPTIMIZE_ALPHA enabled. The palette compositing code in png_init_read_transformations incorrectly applies background compositing during premultiplication, violating the invariant component ≤ alpha × 257 required by the simplified PNG API.
Technical Analysis
In png_init_read_transformations at line ~1336, the palette expansion code performs:
component += (255-alpha)*png_sRGB_table[outrow[c]];
This calculation produces component values up to 16,776,960 (0x1000800), where (component >> 15) == 512. The subsequent PNG_sRGB_FROM_LINEAR macro in png_image_read_composite performs out-of-bounds array access:
png_sRGB_base[component>>15] // Accesses png_sRGB_base[512]
png_sRGB_delta[component>>15] // Accesses png_sRGB_delta[512]
// Both arrays have indices 0-511 only (size 512)
Root Cause: The palette logic fails to distinguish between two execution modes:
- Non-optimized path: Background compositing during palette expansion (correct)
- Optimized path (
PNG_FLAG_OPTIMIZE_ALPHA): Premultiplication only, with background compositing deferred to png_image_read_composite (violated)
Attack Scenario
- Attacker crafts PNG with palette mode (color type 3) and transparency chunk (tRNS).
- Victim application uses simplified API (
png_image_begin_read_from_* + png_image_finish_read) with alpha-capable format (e.g., PNG_FORMAT_RGBA).
- Library enables
PNG_FLAG_OPTIMIZE_ALPHA internally for formats with alpha channel.
- Palette expansion performs premultiplication with background compositing, violating
component ≤ alpha × 257 invariant.
- Out-of-bounds access via
PNG_sRGB_FROM_LINEAR macro in png_image_read_composite.
- Result: Information disclosure via global buffer over-read and/or application crash.
Impact
- Information disclosure via out-of-bounds read of adjacent memory (CWE-125)
- Denial of service (application crash)
Remediation
Upgrade to libpng 1.6.51 or newer.
No practical workaround is available. While avoiding alpha-capable formats (e.g., PNG_FORMAT_RGBA) would prevent the vulnerability by not triggering PNG_FLAG_OPTIMIZE_ALPHA, this defeats the purpose of applications requiring alpha channel data. Upgrade is the recommended remediation.
Proof of Concept
Fuzzer input: https://github.com/pnggroup/libpng/files/20434505/issue-1.zip
AddressSanitizer output:
ERROR: AddressSanitizer: global-buffer-overflow
READ of size 2 at 0x00456b00
in png_image_read_composite pngread.c:3566:37
0x00456b00 is located 0 bytes after global variable 'png_sRGB_base'
Fix
PR #751 introduces conditional behavior in png_init_read_transformations:
if (PNG_FLAG_OPTIMIZE_ALPHA is set)
// Pure premultiplication only
component = (component * alpha + 127) / 255;
else
// Original background compositing
component = png_composite(component, png_sRGB_table[...], alpha);
This ensures component ≤ (alpha × 257), guaranteeing (component >> 15) ≤ 1, well within the valid array bound of 511.
References
An out-of-bounds read vulnerability exists in
png_image_read_compositewhen processing palette images withPNG_FLAG_OPTIMIZE_ALPHAenabled. The palette compositing code inpng_init_read_transformationsincorrectly applies background compositing during premultiplication, violating the invariantcomponent ≤ alpha × 257required by the simplified PNG API.Technical Analysis
In
png_init_read_transformationsat line ~1336, the palette expansion code performs:This calculation produces
componentvalues up to 16,776,960 (0x1000800), where(component >> 15) == 512. The subsequentPNG_sRGB_FROM_LINEARmacro inpng_image_read_compositeperforms out-of-bounds array access:Root Cause: The palette logic fails to distinguish between two execution modes:
PNG_FLAG_OPTIMIZE_ALPHA): Premultiplication only, with background compositing deferred topng_image_read_composite(violated)Attack Scenario
png_image_begin_read_from_*+png_image_finish_read) with alpha-capable format (e.g.,PNG_FORMAT_RGBA).PNG_FLAG_OPTIMIZE_ALPHAinternally for formats with alpha channel.component ≤ alpha × 257invariant.PNG_sRGB_FROM_LINEARmacro inpng_image_read_composite.Impact
Remediation
Upgrade to libpng 1.6.51 or newer.
No practical workaround is available. While avoiding alpha-capable formats (e.g.,
PNG_FORMAT_RGBA) would prevent the vulnerability by not triggeringPNG_FLAG_OPTIMIZE_ALPHA, this defeats the purpose of applications requiring alpha channel data. Upgrade is the recommended remediation.Proof of Concept
Fuzzer input: https://github.com/pnggroup/libpng/files/20434505/issue-1.zip
AddressSanitizer output:
Fix
PR #751 introduces conditional behavior in
png_init_read_transformations:This ensures
component ≤ (alpha × 257), guaranteeing(component >> 15) ≤ 1, well within the valid array bound of 511.References