Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-62986

CVE-2026-62986: OpenEXR Information Disclosure Vulnerability

CVE-2026-62986 is an information disclosure flaw in OpenEXR Python bindings that exposes uninitialized heap data when reading crafted deep scanline EXR files. This post explains its technical details, affected versions, impact, and mitigation steps.

Updated:

CVE-2026-62986 Overview

CVE-2026-62986 is an information disclosure vulnerability in the PyOpenEXR Python bindings of OpenEXR, the reference implementation for the EXR image file format used in motion picture production. The flaw affects versions 3.3.0 through 3.3.12 and 3.4.0 through 3.4.13. When PyOpenEXR reads a crafted deep scanline EXR file that uses layer-prefixed RGB channels, the wrapper returns stale heap contents to Python. Applications that log, serialize, or preview NumPy sample arrays from untrusted EXR files may expose uninitialized same-process memory. The issue is classified as [CWE-200] Information Exposure and has an EPSS score of 0.233%.

Critical Impact

Python applications parsing untrusted deep EXR files through the default OpenEXR.File API can leak uninitialized process heap memory alongside corrupted green and blue channel data.

Affected Products

  • OpenEXR PyOpenEXR bindings 3.3.0 through 3.3.12
  • OpenEXR PyOpenEXR bindings 3.4.0 through 3.4.13
  • Python applications consuming deep scanline EXR files via OpenEXR.File with default separate_channels=False

Discovery Timeline

  • 2026-08-25 - CVE-2026-62986 published to NVD
  • 2026-08-25 - Last updated in NVD database

Technical Details for CVE-2026-62986

Vulnerability Analysis

The vulnerability resides in PyPart::setDeepSliceData() within the PyOpenEXR C++ wrapper. When the wrapper coalesces channels into RGB sample arrays under the default separate_channels=False setting, it computes a per-channel lane offset to determine where decoded pixel values are written. The offset logic uses exact string comparisons against G, B, and A. Layer-prefixed channel names such as left.G and left.B never match, so all prefixed channels are decoded into lane 0. Lanes 1 and 2 remain uninitialized and retain whatever heap contents existed before allocation. Those bytes are then returned to Python as valid NumPy array elements. Downstream code paths that log or serialize the arrays expose the leaked memory to attackers or external systems.

Root Cause

The root cause is an incomplete channel-name comparison in the deep RGB coalescing path. The original implementation uses strcmp(c.name(), "G") and equivalent checks that reject any layer prefix. Because uninitialized lanes are never overwritten and the buffer allocator does not zero memory, prior heap data persists into the returned array.

Attack Vector

Exploitation requires an attacker to deliver a crafted deep scanline EXR file that uses layer-prefixed RGB channels. A victim application must open the file through the default OpenEXR.File API. The attacker cannot directly read the leaked bytes; they must observe them through side channels such as logs, previews, network serialization, or rendered output produced by the target application. User interaction is required to trigger the file load.

cpp
         size_t channel_offset = 0;
         if (C._nrgba > 0)
         {
-            if (!strcmp(c.name(), "G"))
+            char last = c.name()[strlen(c.name()) - 1];
+            if (last == 'G')
                 channel_offset = 1;
-            else if (!strcmp(c.name(), "B"))
+            else if (last == 'B')
                 channel_offset = 2;
-            else if (!strcmp(c.name(), "A"))
+            else if (last == 'A')
                 channel_offset = 3;
         }

Source: OpenEXR patch commit 36ff0968. The patch replaces exact-name comparison with a last-character check, correctly routing prefixed channels such as left.G and left.B to their intended lanes.

Detection Methods for CVE-2026-62986

Indicators of Compromise

  • Deep scanline EXR files containing layer-prefixed channel names such as <layer>.R, <layer>.G, and <layer>.B sourced from untrusted origins.
  • Python processes importing OpenEXR at versions 3.3.0–3.3.12 or 3.4.0–3.4.13 while ingesting external EXR content.
  • NumPy arrays produced from EXR reads that contain high-entropy or non-image values in the green and blue channels.

Detection Strategies

  • Inventory installed Python environments and identify OpenEXR package versions using pip show openexr or SBOM tooling.
  • Instrument EXR ingestion pipelines to log input file provenance and flag deep scanline files with prefixed channel naming.
  • Statistically compare R, G, and B channel distributions on parsed frames; large divergence between R and G/B may indicate the bug is triggering.

Monitoring Recommendations

  • Alert on outbound transfers, logs, or object storage writes containing raw NumPy dumps of EXR channel data.
  • Track application crashes, malformed frames, or downstream renderer errors that correlate with newly ingested EXR assets.
  • Monitor package management events that install or downgrade OpenEXR to affected versions.

How to Mitigate CVE-2026-62986

Immediate Actions Required

  • Upgrade PyOpenEXR to version 3.3.13 or 3.4.14, which contain the corrected lane-offset logic.
  • Audit pipelines that log, serialize, or transmit NumPy arrays produced by OpenEXR.File and purge historical outputs that may contain leaked heap data.
  • Restrict ingestion of deep scanline EXR files to trusted sources until patched versions are deployed.

Patch Information

The OpenEXR maintainers released fixes across the 3.3.x and 3.4.x branches. Reference the following upstream commits: 36ff0968, 51058095, and 5a534e22. Full advisory details are published in the GitHub Security Advisory GHSA-pf59-r2mc-x746.

Workarounds

  • Pass separate_channels=True to the OpenEXR.File constructor so that channels are not coalesced into RGB sample arrays.
  • Zero-initialize or discard the green and blue lanes of decoded arrays when the source file uses layer-prefixed channels.
  • Pre-validate EXR headers and reject files containing deep scanline parts with prefixed R, G, B, or A channel names.
bash
# Upgrade PyOpenEXR to a fixed release
pip install --upgrade "openexr>=3.4.14"

# Or, for the 3.3.x branch
pip install --upgrade "openexr>=3.3.13,<3.4"

# Temporary workaround: force per-channel decoding
python -c "import OpenEXR; f = OpenEXR.File('input.exr', separate_channels=True)"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.