GHSA-7hgm-jxjc-6hgg on CTRL-OS 26.05
Aliases: GHSA-7hgm-jxjc-6hgg
Packages: openexr
Status: Plausible
Advisory Information
OpenEXR v3.4.13 NO_COMPRESSION scanline short chunk uninitialized pixel disclosure
Summary
A crafted scanline EXR using
NO_COMPRESSIONcan declare a chunkpacked_sizesmaller than the computedunpacked_size. In the generic OpenEXRCore decode path, OpenEXR allocates a full-size unpack buffer but does not populate or zero-fill it for this short uncompressed chunk. The later unpack routine then copies bytes from that uninitialized internal buffer into caller-visible pixel output.This is a file-triggered information disclosure issue. It does not require an invalid caller buffer.
Reproduction status
- v3.4.13
exrcheckoriginal/ASAN/UBSAN accepts the crafted file asOK.- v3.4.13 original/ASAN/UBSAN/MSAN public API harnesses accept the safe control and detect allocator-pattern disclosure on the PoC.
- A local main build in this workspace shows the same harness result.
- Freshly fetched
origin/maincommit6820342(Fix Name::operator= to null-terminate long strings (#2500), 2026-06-23) also reproduces in a fresh Release build:exrcheckreturns0, safe control returns0, PoC harness returns134after detecting disclosure.Technical details
The expected invariant is:
For scanline chunks with
compression = NO_COMPRESSION,packed_sizeshould equal the computedunpacked_size, or the decoder must reject/zero-fill before generic unpack reads the full unpacked region.In v3.4.13, the scanline chunk-info path accepts a short nonzero packed size as long as it is not larger than the per-chunk unpacked size:
src/lib/OpenEXRCore/chunk.ccomputes scanlineunpacked_size.- The scanline path rejects
packed_size == 0, but does not reject0 < packed_size < unpacked_sizeforNO_COMPRESSION.- The tile path has a stricter
NO_COMPRESSIONpacked/unpacked equality check, but the scanline path lacks the equivalent check.The generic decode path is then reachable with a normal non-direct output layout, such as padded pixel stride:
src/lib/OpenEXRCore/decoding.callocatesdecode->unpacked_bufferwhenpacked_size != unpacked_size.- For
EXR_COMPRESSION_NONE, no decompressor copies short packed data into that full buffer.exr_decoding_run()still invokes the selected unpack routine becausechunk.unpacked_size > 0.src/lib/OpenEXRCore/unpack.creads fromdecode->unpacked_bufferand writes those bytes to the caller's output channel.The PoC file is a 64x1 single-channel FLOAT scanline EXR with
NO_COMPRESSION. The safe control haspacked_size = unpacked_size = 256. The PoC changes the first chunk leader'spacked_sizeto16while keeping the file otherwise structurally valid enough forexrcheckto reportOK.PoC files
poc.zipcontains only the files needed to reproduce and inspect the issue:
reproduce.sh— replay script for the local v3.4.13/main harness builds.poc_materials/base_none_64x1_float.exr— safe control.poc_materials/poc_none_short_16_of_256.exr— crafted short uncompressed scanline chunk.poc_materials/make_none_base.cpp— safe-control generator.poc_materials/patch_none_short.py— packed-size patcher.poc_materials/fuzz_none_short_uncompressed_api.cpp— focused public OpenEXRCore API harness.poc_materials/logs/final/— full current reproduction logs.Run from this report directory:
./reproduce.shCurrent reproduction output
Full stdout from the current replay:
===== exrcheck_original_poc ===== rc=0 file /home/br0nzu/openexr/v3.4.13/report/39. OpenEXR v3.4.13 NO_COMPRESSION scanline short chunk uninitialized pixel disclosure/poc_materials/poc_none_short_16_of_256.exr OK ===== exrcheck_asan_poc ===== rc=0 file /home/br0nzu/openexr/v3.4.13/report/39. OpenEXR v3.4.13 NO_COMPRESSION scanline short chunk uninitialized pixel disclosure/poc_materials/poc_none_short_16_of_256.exr OK ===== exrcheck_ubsan_poc ===== rc=0 file /home/br0nzu/openexr/v3.4.13/report/39. OpenEXR v3.4.13 NO_COMPRESSION scanline short chunk uninitialized pixel disclosure/poc_materials/poc_none_short_16_of_256.exr OK ===== v3413_original_base ===== rc=0 ===== v3413_original_poc ===== rc=134 NO_COMPRESSION short chunk leaked allocator pattern into channel 0: 256/256 written bytes (528 payload bytes) ===== v3413_asan_base ===== rc=0 ===== v3413_asan_poc ===== rc=134 NO_COMPRESSION short chunk leaked allocator pattern into channel 0: 256/256 written bytes (528 payload bytes) ===== v3413_ubsan_base ===== rc=0 ===== v3413_ubsan_poc ===== rc=134 NO_COMPRESSION short chunk leaked allocator pattern into channel 0: 256/256 written bytes (528 payload bytes) ===== v3413_msan_base ===== rc=0 ===== v3413_msan_poc ===== rc=134 NO_COMPRESSION short chunk leaked allocator pattern into channel 0: 256/256 written bytes (528 payload bytes) ===== local_main_original_base ===== rc=0 ===== local_main_original_poc ===== rc=134 NO_COMPRESSION short chunk leaked allocator pattern into channel 0: 256/256 written bytes (528 payload bytes) ===== local_main_asan_base ===== rc=0 ===== local_main_asan_poc ===== rc=134 NO_COMPRESSION short chunk leaked allocator pattern into channel 0: 256/256 written bytes (528 payload bytes) ===== local_main_ubsan_base ===== rc=0 ===== local_main_ubsan_poc ===== rc=134 NO_COMPRESSION short chunk leaked allocator pattern into channel 0: 256/256 written bytes (528 payload bytes) ===== local_main_msan_base ===== rc=0 ===== local_main_msan_poc ===== rc=134 NO_COMPRESSION short chunk leaked allocator pattern into channel 0: 256/256 written bytes (528 payload bytes)Latest fetched
origin/mainfresh Release build:origin/main commit: 6820342 2026-06-23 15:24:29 -0700 Fix Name::operator= to null-terminate long strings (#2500) exrcheck poc rc=0 harness base rc=0 harness poc rc=134 file /home/br0nzu/openexr/v3.4.13/report/39. OpenEXR v3.4.13 NO_COMPRESSION scanline short chunk uninitialized pixel disclosure/poc_materials/poc_none_short_16_of_256.exr OK NO_COMPRESSION short chunk leaked allocator pattern into channel 0: 256/256 written bytes (528 payload bytes)Impact
An attacker who can supply an EXR image to an application that decodes pixels through OpenEXRCore into a non-direct but valid output layout can cause caller-visible decoded pixels to contain stale internal allocation bytes rather than file-provided samples. Applications that display, save, transform, or transmit decoded pixels may expose those bytes.
This report demonstrates information disclosure through decoded pixel output. The harness abort is intentional after detecting the disclosure.
Suggested fix
For scanline chunks, mirror the tile-path invariant for
EXR_COMPRESSION_NONE: reject chunks wherepacked_size != unpacked_size, or explicitly initialize/copy/zero-fill the full unpack buffer before any generic unpack routine can read from it.
Updates
2026-08-11 03:50 CEST
Metadata changes:
- Status for package
openexr: “Plausible”
2026-08-11 03:32 CEST
Metadata changes:
- Status for package
openexr: “New”