Описание
OpenEXR has a signed 32-bit Overflow in PIZ Decoder Leads to OOB Read/Write
Summary
internal_exr_undo_piz() advances the working wavelet pointer with signed 32-bit arithmetic:
Because nx, ny, and wcount are int, a crafted EXR file can make this product overflow and wrap. The next channel then decodes from an incorrect address. The wavelet decode path operates in place, so this yields both out-of-bounds reads and out-of-bounds writes.
Tested on commit 7820b7e1b93405ba1d551c43a945018226b75bc5
Technical Details
The vulnerable decode path is:
internal_exr_undo_piz()setswavbuf = decode->scratch_buffer_1.- For each channel, it calls
wav_2D_decode (wavbuf + j, ...). - It then advances
wavbufwithwavbuf += nx * ny * wcount.
The overflow happens in step 3. Once wavbuf is wrapped, the next channel's wavelet decode runs on the wrong address.
In the 14-bit wavelet path, wdec14_4() first reads:
*px*p10*p01*p11
and then writes back to the same locations:
*px = ...*p01 = ...*p10 = ...*p11 = ...
As a result, the bug is not just a crash-only invalid read. It is an out-of-bounds read/write condition.
Reproduction
Build exrcheck with ASAN and run:
To prove this is both READ and WRITE, we can also memcheck against non-ASAN release build:
Observed result:
Invalid read of size 2at internal_piz.c:150Invalid write of size 2at internal_piz.c:171
This confirms the bug is an OOB read/write, not only a read-first crash.
Redzone-Oriented File
- width:
67108862 - height:
32 - channel A:
FLOAT, sampling1 x 1 - channel B:
HALF, sampling33554431 x 16
This makes:
which wraps signed 32-bit arithmetic to -128.
That places the next wavbuf access just before the allocated buffer, producing a clean heap-overflow report.
Impact
A crafted EXR file can trigger out-of-bounds memory access during PIZ decompression. The primitive includes both invalid reads and invalid writes. Depending on allocator layout and surrounding memory, this could lead to process crash, memory corruption, or potentially stronger exploitation outcomes.
Recommended Fix
- compute channel span in 64-bit arithmetic
- reject any overflow in
nx * ny * wcount - validate cumulative per-channel decoded footprint against
outszbefore wavelet decode - fail decompression if channel-derived layout does not exactly fit the decompression buffer
Found by: Quang Luong of Calif.io
Ссылки
- https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-588r-cr5c-w6hf
- https://nvd.nist.gov/vuln/detail/CVE-2026-34588
- https://github.com/AcademySoftwareFoundation/openexr/releases/tag/v3.2.7
- https://github.com/AcademySoftwareFoundation/openexr/releases/tag/v3.3.9
- https://github.com/AcademySoftwareFoundation/openexr/releases/tag/v3.4.9
Пакеты
OpenEXR
>= 3.1.0, < 3.2.7
3.2.7
OpenEXR
>= 3.3.0, < 3.3.9
3.3.9
OpenEXR
>= 3.4.0, < 3.4.9
3.4.9
EPSS
8.6 High
CVSS4
7.8 High
CVSS3
CVE ID
Дефекты
Связанные уязвимости
OpenEXR provides the specification and reference implementation of the EXR file format, an image storage format for the motion picture industry. From 3.1.0 to before 3.2.7, 3.3.9, and 3.4.9, internal_exr_undo_piz() advances the working wavelet pointer with signed 32-bit arithmetic. Because nx, ny, and wcount are int, a crafted EXR file can make this product overflow and wrap. The next channel then decodes from an incorrect address. The wavelet decode path operates in place, so this yields both out-of-bounds reads and out-of-bounds writes. This vulnerability is fixed in 3.2.7, 3.3.9, and 3.4.9.
OpenEXR provides the specification and reference implementation of the EXR file format, an image storage format for the motion picture industry. From 3.1.0 to before 3.2.7, 3.3.9, and 3.4.9, internal_exr_undo_piz() advances the working wavelet pointer with signed 32-bit arithmetic. Because nx, ny, and wcount are int, a crafted EXR file can make this product overflow and wrap. The next channel then decodes from an incorrect address. The wavelet decode path operates in place, so this yields both out-of-bounds reads and out-of-bounds writes. This vulnerability is fixed in 3.2.7, 3.3.9, and 3.4.9.
OpenEXR provides the specification and reference implementation of the EXR file format, an image storage format for the motion picture industry. From 3.1.0 to before 3.2.7, 3.3.9, and 3.4.9, internal_exr_undo_piz() advances the working wavelet pointer with signed 32-bit arithmetic. Because nx, ny, and wcount are int, a crafted EXR file can make this product overflow and wrap. The next channel then decodes from an incorrect address. The wavelet decode path operates in place, so this yields both out-of-bounds reads and out-of-bounds writes. This vulnerability is fixed in 3.2.7, 3.3.9, and 3.4.9.
OpenEXR provides the specification and reference implementation of the ...
EPSS
8.6 High
CVSS4
7.8 High
CVSS3