Skip to content

GHSA-2f85-52wj-hc3c

CVE Information

Summary

A crafted HTJ2K-compressed EXR file causes an unconditional process abort (SIGABRT) in any application calling exr_start_read() on untrusted input. The trigger is a QCD marker with Sqcd & 0x1F = 0. OpenEXR's ht_undo_impl() calls cs.create() on the parsed codestream, which invokes param_qcd::get_irrev_delta() in the vendored OpenJPH 0.26.3 library. That function contains assert((Sqcd & 0x1F) == 2) — an assert() instead of OJPH_ERROR() — which calls abort() and cannot be caught by any try/catch block.

Details

Two-part root cause:

(A) external/OpenJPH/src/core/codestream/ojph_params.cpp, line 1408: assert((Sqcd & 0x1F) == 2); // unconditional abort, not catchable Every other invalid-marker condition in the same file uses OJPH_ERROR().

(B) src/lib/OpenEXRCore/internal_ht.cpp — ht_undo_impl() wraps only the internal HT header parser (lines 175–183) in try/catch. The calls cs.read_headers() (line 218) and cs.create() (line 257) are unprotected.

Upstream fix: OpenJPH commit 871c6ad (released in OpenJPH 0.27.1, 2026-05-07) replaces the assert with OJPH_ERROR(). This commit has no CVE and no advisory. OpenEXR's vendored copy (0.26.3) predates it.

Proposed fix — Fix A: cherry-pick 871c6ad into external/OpenJPH or update to ≥ 0.27.1. Fix B: wrap cs.read_headers() and cs.create() in try/catch returning EXR_ERR_CORRUPT_CHUNK. Both fixes tested and verified — crafted file returns EXR_ERR_CORRUPT_CHUNK, valid files unaffected.

Tested on HEAD commit bd61413.

PoC

Minimized 82-byte J2K codestream (prepend 10-byte HT header: 48 54 00 00 00 04 00 01 00 00):

ff4f ff51 0029 c200 0000 0008 0000 0008 0000 0000 0000 0000 0000 0008 0000 0008 0000 0000 0000 0000 0001 8f01 01ff 5200 0c00 0200 0100 0505 0340 00ff 5c00 1320 8880 9090 9090 9090 90ff ffff ffff ffff ff90

Triggering byte: offset +63 (0x20 = Sqcd, lower 5 bits = 0).

Reproduce: build exrcheck from HEAD with Debug flags, construct 431-byte EXR (valid 8×8 HTJ2K32 skeleton with chunk body replaced by HT header + codestream above), run: ./build/bin/exrcheck crafted.exr Expected: Assertion `(Sqcd & 0x1F) == 2' failed. [exit 134 / SIGABRT]

Impact

Denial of service: any process opening an untrusted HTJ2K-compressed EXR file aborts unconditionally. No memory corruption, no information disclosure, no code execution. CVSS 3.1: AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H — Base Score 6.5 (Medium). Affects all OpenEXR versions with vendored OpenJPH < 0.27.1.