# OpenEXR: DWA Lossy Decoder Heap Out-of-Bounds Write

Signed 32-bit overflow in OpenEXR DWA lossy decoder's rowBlock pointer arithmetic wraps per-component pointers, causing heap out-of-bounds write during DCT reconstruction from a crafted DWAA file.

- Payout: Research
- Severity: high
- Program: OpenEXR
- Found by: quangIO
- Disclosed: 2026-04-08
- CVE: CVE-2026-34589
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-p8xc-w3q4-h64x
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-p8xc-w3q4-h64x
- Tags: area:oss domain:oss impact:dos kind:research platform:ghsa sev:high tech:python technique:fuzzing technique:source-review vuln:dos vuln:memory-corruption

**Target:** DWA lossy decoder (internal_dwa_decoder.h) via exrcheck / ScanLineInputFile read path
**Root cause:** `rowBlock[comp] = rowBlock[comp-1] + numBlocksX * 64` computes `numBlocksX * 64` in signed 32-bit int; for large widths the multiply wraps, so derived per-component pointers point backward outside the rowBlockHandle allocation. LossyDctDecoder_execute then performs real loads/stores through those wrapped pointers.
**Steps:**
1. Build OpenEXR with ASAN/UBSan and the `exrcheck` tool.
2. Craft a scanline DWAA (DWA lossy) EXR with a width large enough that `numBlocksX * 64` overflows signed int (e.g. 33554432 * 64).
3. Run `./build-asan/bin/exrcheck /tmp/dwa_scanline_exrcheck.exr`.
4. UBSan reports signed integer overflow at internal_dwa_decoder.h:331; ASAN reports SEGV on WRITE in LossyDctDecoder_execute at internal_dwa_decoder.h:524.
**How found:** Reporter audited the DWA decoder's per-component pointer construction and noticed the `numBlocksX * 64` stride is computed in signed int; hypothesized overflow for large widths, then confirmed with UBSan (overflow) and ASAN (write-side crash) using a crafted DWAA scanline file.
**Exploitation:** Attacker supplies a malicious DWAA-compressed EXR; any consumer reading it via the public InputFile/ScanLineInputFile path (or exrcheck) triggers the wrapped pointer and an out-of-bounds write during DCT block shuffle/reconstruction, crashing the process (write-side SEGV). No further weaponization described.
**Insight:** In image/codec decoders, per-component or per-row pointer strides derived from attacker-controlled dimensions are prime overflow sites: check whether stride multiplications use signed int before trusting derived pointers, and fuzz width/height extremes rather than only malformed headers.

## Proof of concept (copied exactly from the original report)

**exrcheck command on crafted DWAA file**

```
./build-asan/bin/exrcheck /tmp/dwa_scanline_exrcheck.exr
 file /tmp/dwa_scanline_exrcheck.exr /home/pop/sec/openexr/src/lib/OpenEXRCore/internal_dwa_decoder.h:331:58: runtime error: signed integer overflow: 33554432 * 64 cannot be represented in type 'int'
AddressSanitizer:DEADLYSIGNAL
=================================================================
==1684058==ERROR: AddressSanitizer: SEGV on unknown address 0x758f8e5f0800 (pc 0x75979e850336 bp 0x7ffe8f1d3420 sp 0x7ffe8f1d30f0 T0)
==1684058==The signal is caused by a WRITE memory access.
```

