From 316993443baa91bd90ca50f8a67c1da3d91278b9 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Thu, 11 Jun 2026 19:52:48 -0700 Subject: [PATCH 01/63] Fix install manifest for linux build 13 (#2466) The hard-coded 4_0 release number in the new install manifest should have been converted to a symbolic value. Signed-off-by: Cary Phillips --- .../ci/install_manifest/install_manifest.linux.13.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/share/ci/install_manifest/install_manifest.linux.13.txt b/share/ci/install_manifest/install_manifest.linux.13.txt index 2e8862393..e64130735 100644 --- a/share/ci/install_manifest/install_manifest.linux.13.txt +++ b/share/ci/install_manifest/install_manifest.linux.13.txt @@ -164,11 +164,11 @@ lib64/cmake/OpenEXR/OpenEXRConfig.cmake lib64/cmake/OpenEXR/OpenEXRConfigVersion.cmake lib64/cmake/OpenEXR/OpenEXRTargets-release.cmake lib64/cmake/OpenEXR/OpenEXRTargets.cmake -lib64/libIex-4_0.a -lib64/libIlmThread-4_0.a -lib64/libOpenEXR-4_0.a -lib64/libOpenEXRCore-4_0.a -lib64/libOpenEXRUtil-4_0.a +lib64/libIex-${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}.a +lib64/libIlmThread-${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}.a +lib64/libOpenEXR-${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}.a +lib64/libOpenEXRCore-${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}.a +lib64/libOpenEXRUtil-${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}.a lib64/pkgconfig/OpenEXR.pc share/doc/OpenEXR/examples/deepExamples.cpp share/doc/OpenEXR/examples/deepExamples.h From 5d799be5fab557858145a36002edbfe9989d20fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 21:52:48 -0700 Subject: [PATCH 02/63] Bump sigstore/gh-action-sigstore-python from 3.3.0 to 3.4.0 (#2467) Bumps [sigstore/gh-action-sigstore-python](https://github.com/sigstore/gh-action-sigstore-python) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/sigstore/gh-action-sigstore-python/releases) - [Changelog](https://github.com/sigstore/gh-action-sigstore-python/blob/main/CHANGELOG.md) - [Commits](https://github.com/sigstore/gh-action-sigstore-python/compare/04cffa1d795717b140764e8b640de88853c92acc...5b79a39c381910c090341a2c9b0bf022c8b387e1) --- updated-dependencies: - dependency-name: sigstore/gh-action-sigstore-python dependency-version: 3.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release-sign.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-sign.yml b/.github/workflows/release-sign.yml index 11a289cdf..f0cc50820 100644 --- a/.github/workflows/release-sign.yml +++ b/.github/workflows/release-sign.yml @@ -63,7 +63,7 @@ jobs: run: git archive --format=tar.gz -o ${OPENEXR_TARBALL} --prefix ${OPENEXR_PREFIX} ${TAG} - name: Sign archive with Sigstore - uses: sigstore/gh-action-sigstore-python@04cffa1d795717b140764e8b640de88853c92acc # v3.3.0 + uses: sigstore/gh-action-sigstore-python@5b79a39c381910c090341a2c9b0bf022c8b387e1 # v3.4.0 with: inputs: ${{ env.OPENEXR_TARBALL }} upload-signing-artifacts: false From 0565c021ae6fd84facedeabac6743cad08e8f202 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Fri, 12 Jun 2026 18:18:29 -0700 Subject: [PATCH 03/63] Add section on CVE Assignment to SECURITY.md (#2471) --- SECURITY.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/SECURITY.md b/SECURITY.md index 2ed1eaad4..f613e5de9 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,6 +16,24 @@ Our policy is to acknowledge the receipt of vulnerability reports within 48 hours. Our policy is to address critical security vulnerabilities rapidly and post patches within 14 days if possible. +## CVE Assignment + +We request a CVE when an untrusted party can plausibly trigger the flaw +through normal product inputs (for example, a crafted EXR or other data +the application is meant to process); otherwise we treat it as a regular +bugfix, document it in a GitHub security advisory or release notes when +helpful, and do not request a CVE for API-only or caller-controlled +failures with no realistic adversarial path. + +Flaws whose root cause lies in a bundled dependency (such as OpenJPH) +are fixed upstream; the upstream project owns the CVE when one is +warranted. Note that this applies even when a flaw is detected in +dependency code vendored into OpenEXR's `external/` source directory. +OpenEXR addresses them by updating the dependency and noting the +upstream advisory in release notes. We request a CVE for OpenEXR +itself only when the flaw is in our code and untrusted input can reach +it through normal use of the library. + ## Known Vulnerabilities | CVE | Affected Versions | Patched Versions | From 176c97870cc1943bf1756c6fc583eb8eedea8a96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 20:02:08 -0700 Subject: [PATCH 04/63] Bump msys2/setup-msys2 from 2.31.1 to 2.32.0 (#2474) Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.31.1 to 2.32.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/e9898307ac31d1a803454791be09ab9973336e1c...66cd2cce69caa17b53920067426061ca1de3a884) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.32.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci_steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_steps.yml b/.github/workflows/ci_steps.yml index fa172df64..4a20ec73c 100644 --- a/.github/workflows/ci_steps.yml +++ b/.github/workflows/ci_steps.yml @@ -161,7 +161,7 @@ jobs: - name: Install MSYS2 ${{ inputs.msystem }} if: inputs.msystem != '' - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # v2.31.1 + uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2.32.0 with: msystem: ${{ inputs.msystem }} update: true From c064306b7eca8c08f151e7262bc77658f77f46c1 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Tue, 16 Jun 2026 19:37:06 -0700 Subject: [PATCH 05/63] Fix infinite loop in SampleCountChannel roundListSizeUp() (#2468) Reject sample counts above 0x80000000 before rounding up to the next power of two, since larger values cause the unsigned shift loop to wrap and never terminate. Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXRUtil/ImfSampleCountChannel.cpp | 9 ++++ src/test/OpenEXRUtilTest/testDeepImage.cpp | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/lib/OpenEXRUtil/ImfSampleCountChannel.cpp b/src/lib/OpenEXRUtil/ImfSampleCountChannel.cpp index 5e5a90892..fd6acab12 100644 --- a/src/lib/OpenEXRUtil/ImfSampleCountChannel.cpp +++ b/src/lib/OpenEXRUtil/ImfSampleCountChannel.cpp @@ -32,6 +32,15 @@ roundListSizeUp (unsigned int n) if (n == 0) return 0; + if (n > 0x80000000u) + { + THROW ( + ArgExc, + "Sample count " + << n + << " is too large (cannot round up to next power of two)"); + } + unsigned int s = 1; while (s < n) diff --git a/src/test/OpenEXRUtilTest/testDeepImage.cpp b/src/test/OpenEXRUtilTest/testDeepImage.cpp index 4be23c7a2..6f48aef86 100644 --- a/src/test/OpenEXRUtilTest/testDeepImage.cpp +++ b/src/test/OpenEXRUtilTest/testDeepImage.cpp @@ -15,6 +15,7 @@ #include #include +#include #include using namespace OPENEXR_IMF_NAMESPACE; @@ -698,6 +699,46 @@ testRenameChannels () assert (caught); } +void +testRoundListSizeUpLimits () +{ + cout << " roundListSizeUp limits" << endl; + + auto expectArgExc = [] (auto&& fn) { + bool caught = false; + try + { + fn (); + } + catch (const ArgExc&) + { + caught = true; + } + assert (caught); + }; + + expectArgExc ([&] { + DeepImage img; + img.resize (Box2i (V2i (0, 0), V2i (0, 0)), ONE_LEVEL, ROUND_DOWN); + img.level (0).sampleCounts ().set (0, 0, UINT_MAX); + }); + + expectArgExc ([&] { + DeepImage img; + img.resize (Box2i (V2i (0, 0), V2i (0, 0)), ONE_LEVEL, ROUND_DOWN); + img.level (0).sampleCounts ().set (0, 0, 0x80000001u); + }); + + expectArgExc ([&] { + DeepImage img; + img.resize (Box2i (V2i (0, 0), V2i (0, 0)), ONE_LEVEL, ROUND_DOWN); + SampleCountChannel& samples = img.level (0).sampleCounts (); + unsigned int* counts = samples.beginEdit (); + counts[0] = UINT_MAX; + samples.endEdit (); + }); +} + } // namespace void @@ -711,6 +752,7 @@ testDeepImage (const string& tempDir) testTiledImages (tempDir + "deepTiles.exr"); testSetSampleCounts (); testSetSampleCountRowOffset (); + testRoundListSizeUpLimits (); testShiftPixels (); testCropping (tempDir + "deepCropped.exr"); testRenameChannel (); From 808e2eb25e694b0fb5fedb371f5bd2eca956df04 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Tue, 16 Jun 2026 19:39:52 -0700 Subject: [PATCH 06/63] Reject NULL bytes type_hint and data in exr_attr_bytes_create() (#2470) Validate non-null pointers when hint length or data size is non-zero, and apply the same checks in the in-place exr_attr_set_bytes() path. Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXRCore/bytes.c | 18 +++++++++++-- src/lib/OpenEXRCore/part_attr.c | 30 +++++++++++++++------ src/test/OpenEXRCoreTest/general_attr.cpp | 33 +++++++++++++++++++++++ 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/src/lib/OpenEXRCore/bytes.c b/src/lib/OpenEXRCore/bytes.c index 7cf2b2593..22bf6428c 100644 --- a/src/lib/OpenEXRCore/bytes.c +++ b/src/lib/OpenEXRCore/bytes.c @@ -76,11 +76,25 @@ exr_attr_bytes_create ( const void* t, const void* d) { + if (h > 0 && !t) + return ctxt->print_error ( + ctxt, + EXR_ERR_INVALID_ARGUMENT, + "Invalid NULL type hint for bytes attribute with hint length %u", + h); + + if (b > 0 && !d) + return ctxt->print_error ( + ctxt, + EXR_ERR_INVALID_ARGUMENT, + "Invalid NULL bytes data for bytes attribute with size %zu", + b); + exr_result_t rv = exr_attr_bytes_init (ctxt, u, h, b); if (rv == EXR_ERR_SUCCESS) { - if (d && u->data) memcpy ((void*) u->data, d, b); - if (d && u->type_hint) memcpy ((void*) u->type_hint, t, h); + if (b > 0 && u->data) memcpy ((void*) u->data, d, b); + if (h > 0 && u->type_hint) memcpy ((void*) u->type_hint, t, h); } return rv; diff --git a/src/lib/OpenEXRCore/part_attr.c b/src/lib/OpenEXRCore/part_attr.c index a3a927042..bf528f589 100644 --- a/src/lib/OpenEXRCore/part_attr.c +++ b/src/lib/OpenEXRCore/part_attr.c @@ -1333,14 +1333,28 @@ exr_attr_set_bytes ( if (attr->bytes->size == val->size && attr->bytes->hint_length == val->hint_length) { - memcpy ( - EXR_CONST_CAST (void*, attr->bytes->type_hint), - val->type_hint, - val->hint_length); - memcpy ( - EXR_CONST_CAST (void*, attr->bytes->data), - val->data, - val->size); + if (val->hint_length > 0 && !val->type_hint) + return EXR_UNLOCK_AND_RETURN (ctxt->print_error ( + ctxt, + EXR_ERR_INVALID_ARGUMENT, + "Invalid NULL type hint for setting '%s'", + name)); + if (val->size > 0 && !val->data) + return EXR_UNLOCK_AND_RETURN (ctxt->print_error ( + ctxt, + EXR_ERR_INVALID_ARGUMENT, + "Invalid NULL bytes data for setting '%s'", + name)); + if (val->hint_length > 0) + memcpy ( + EXR_CONST_CAST (void*, attr->bytes->type_hint), + val->type_hint, + val->hint_length); + if (val->size > 0) + memcpy ( + EXR_CONST_CAST (void*, attr->bytes->data), + val->data, + val->size); } else if (ctxt->mode != EXR_CONTEXT_WRITE && ctxt->mode != EXR_CONTEXT_TEMPORARY) { diff --git a/src/test/OpenEXRCoreTest/general_attr.cpp b/src/test/OpenEXRCoreTest/general_attr.cpp index 23cee09be..78ff201d9 100644 --- a/src/test/OpenEXRCoreTest/general_attr.cpp +++ b/src/test/OpenEXRCoreTest/general_attr.cpp @@ -1027,6 +1027,39 @@ testBytesHelper (exr_context_t f) EXRCORE_TEST_RVAL (exr_attr_bytes_destroy (f, &b2)); EXRCORE_TEST_RVAL (exr_attr_bytes_destroy (f, &b)); + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, + exr_attr_bytes_create (f, &b, 1, 1, NULL, data4)); + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, + exr_attr_bytes_create (f, &b, 0, 4, "hint", NULL)); + + { + exr_attr_bytes_t bytes; + bytes.size = 1; + bytes.data = data4; + bytes.hint_length = 1; + bytes.type_hint = NULL; + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, + exr_attr_set_bytes (f, 0, "badBytes", &bytes)); + } + + { + exr_attr_bytes_t bytes; + bytes.size = 4; + bytes.data = data4; + bytes.hint_length = 11; + bytes.type_hint = "a cool hint"; + EXRCORE_TEST_RVAL ( + exr_attr_set_bytes (f, 0, "goodBytes", &bytes)); + + bytes.type_hint = NULL; + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, + exr_attr_set_bytes (f, 0, "goodBytes", &bytes)); + } + EXRCORE_TEST_RVAL_FAIL ( EXR_ERR_INVALID_ARGUMENT, exr_attr_bytes_copy (f, &b2, NULL)); } From 3794a165d3421e19332dcf544da4d7ae62b81a06 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Tue, 16 Jun 2026 19:40:27 -0700 Subject: [PATCH 07/63] Drop support for Python 3.8 (#2477) 3.8 was never actually included in any vfx reference platform year, and the platform has been at Python 3.9+ since CY2022. And cibuildwheel 4.0 drops support for 3.8. This will take effect in OpenEXR v3.5. Signed-off-by: Cary Phillips --- .github/workflows/python-wheels-publish-test.yml | 4 ++-- .github/workflows/python-wheels-publish.yml | 4 ++-- .github/workflows/python-wheels.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/python-wheels-publish-test.yml b/.github/workflows/python-wheels-publish-test.yml index aa3c588f1..21748c48c 100644 --- a/.github/workflows/python-wheels-publish-test.yml +++ b/.github/workflows/python-wheels-publish-test.yml @@ -97,10 +97,10 @@ jobs: env: MACOSX_DEPLOYMENT_TARGET: 10.15 CIBW_ARCHS_MACOS: x86_64 arm64 universal2 - # Build Python 3.8 through 3.13. + # Build Python 3.9 through 3.13. # Skip 32-bit wheels builds on Windows # Also skip the PyPy builds, since they fail the unit tests - CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-*" + CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-* cp313-*" CIBW_SKIP: "*-win32 *_i686" CIBW_ENVIRONMENT: OPENEXR_RELEASE_CANDIDATE_TAG="${{ github.ref_name }}" diff --git a/.github/workflows/python-wheels-publish.yml b/.github/workflows/python-wheels-publish.yml index eeb176827..c29b44cdf 100644 --- a/.github/workflows/python-wheels-publish.yml +++ b/.github/workflows/python-wheels-publish.yml @@ -91,10 +91,10 @@ jobs: env: MACOSX_DEPLOYMENT_TARGET: 10.15 CIBW_ARCHS_MACOS: x86_64 arm64 universal2 - # Build Python 3.8 through 3.13 + # Build Python 3.9 through 3.13 # Skip 32-bit wheels builds on Windows # Also skip the PyPy builds, since they fail the unit tests - CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-*" + CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-* cp313-*" CIBW_SKIP: "*-win32 *_i686" - name: Upload artifact diff --git a/.github/workflows/python-wheels.yml b/.github/workflows/python-wheels.yml index 4307ec885..8a61c637b 100644 --- a/.github/workflows/python-wheels.yml +++ b/.github/workflows/python-wheels.yml @@ -78,10 +78,10 @@ jobs: output-dir: wheelhouse env: CIBW_ARCHS_MACOS: x86_64 arm64 universal2 - # Build Python 3.8 through 3.13 + # Build Python 3.9 through 3.13 # Skip 32-bit wheels builds on Windows # Also skip the PyPy builds, since they fail the unit tests - CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-*" + CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-* cp313-*" CIBW_SKIP: "*-win32 *_i686" - name: Upload artifact From bc7fc07c2d8555cefbc264f324bc600b274453fc Mon Sep 17 00:00:00 2001 From: vlazar-ilm Date: Wed, 17 Jun 2026 00:12:09 -0400 Subject: [PATCH 08/63] Fix the DWAA size checks (#2476) --- src/lib/OpenEXRCore/internal_dwa_compressor.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/OpenEXRCore/internal_dwa_compressor.h b/src/lib/OpenEXRCore/internal_dwa_compressor.h index 19931f28e..88ec309dc 100644 --- a/src/lib/OpenEXRCore/internal_dwa_compressor.h +++ b/src/lib/OpenEXRCore/internal_dwa_compressor.h @@ -774,8 +774,7 @@ DwaCompressor_uncompress ( be checked below */ if (unknownUncompressedSize > uncompressed_size || rleRawSize > uncompressed_size || - (unknownUncompressedSize + rleRawSize) > uncompressed_size || - totalAcUncompressedCount > uncompressed_size) + (unknownUncompressedSize + rleRawSize) > uncompressed_size) { return EXR_ERR_CORRUPT_CHUNK; } From 1ac9a7b02efd857c656e4e5ac81874873d27adfc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2026 08:25:13 -0700 Subject: [PATCH 09/63] Bump pypa/cibuildwheel from 3.4.1 to 4.1.0 (#2475) Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.4.1 to 4.1.0. - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/8d2b08b68458a16aeb24b64e68a09ab1c8e82084...294735312765b09d24a2fbec22660ce817587d55) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 4.1.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/python-wheels-publish-test.yml | 2 +- .github/workflows/python-wheels-publish.yml | 2 +- .github/workflows/python-wheels.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/python-wheels-publish-test.yml b/.github/workflows/python-wheels-publish-test.yml index 21748c48c..d321b8c43 100644 --- a/.github/workflows/python-wheels-publish-test.yml +++ b/.github/workflows/python-wheels-publish-test.yml @@ -91,7 +91,7 @@ jobs: run: pipx run build==1.2.2.post1 --sdist . --outdir wheelhouse - name: Build wheel - uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0 with: output-dir: wheelhouse env: diff --git a/.github/workflows/python-wheels-publish.yml b/.github/workflows/python-wheels-publish.yml index c29b44cdf..d4719eeb5 100644 --- a/.github/workflows/python-wheels-publish.yml +++ b/.github/workflows/python-wheels-publish.yml @@ -85,7 +85,7 @@ jobs: run: pipx run build==1.2.2.post1 --sdist . --outdir wheelhouse - name: Build wheel - uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0 with: output-dir: wheelhouse env: diff --git a/.github/workflows/python-wheels.yml b/.github/workflows/python-wheels.yml index 8a61c637b..ad0fda065 100644 --- a/.github/workflows/python-wheels.yml +++ b/.github/workflows/python-wheels.yml @@ -73,7 +73,7 @@ jobs: run: pipx run build==1.2.2.post1 --sdist . --outdir wheelhouse - name: Build wheel - uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0 with: output-dir: wheelhouse env: From 7f3ffb87e55e879f62024a06a3d633825628a606 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Wed, 17 Jun 2026 08:27:12 -0700 Subject: [PATCH 10/63] Unlock write context in exr_get_chunk_table_offset() return paths (#2472) EXR_LOCK_WRITE_AND_DEFINE_PART() acquires the mutex on write contexts but both success and error returns leaked the lock, deadlocking later API calls such as exr_get_count(). Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXRCore/chunk.c | 5 +++-- src/test/OpenEXRCoreTest/write.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/lib/OpenEXRCore/chunk.c b/src/lib/OpenEXRCore/chunk.c index 69f8be912..b4f79a498 100644 --- a/src/lib/OpenEXRCore/chunk.c +++ b/src/lib/OpenEXRCore/chunk.c @@ -516,10 +516,11 @@ exr_get_chunk_table_offset ( EXR_LOCK_WRITE_AND_DEFINE_PART (part_index); if (!chunk_offset_out) - return ctxt->standard_error (ctxt, EXR_ERR_INVALID_ARGUMENT); + return EXR_UNLOCK_WRITE_AND_RETURN ( + ctxt->standard_error (ctxt, EXR_ERR_INVALID_ARGUMENT)); *chunk_offset_out = part->chunk_table_offset; - return EXR_ERR_SUCCESS; + return EXR_UNLOCK_WRITE_AND_RETURN (EXR_ERR_SUCCESS); } exr_result_t diff --git a/src/test/OpenEXRCoreTest/write.cpp b/src/test/OpenEXRCoreTest/write.cpp index 374ad0618..6715782fd 100644 --- a/src/test/OpenEXRCoreTest/write.cpp +++ b/src/test/OpenEXRCoreTest/write.cpp @@ -88,6 +88,17 @@ testStartWriteScan (const std::string& tempdir) EXRCORE_TEST_RVAL ( exr_add_part (outf, "beauty", EXR_STORAGE_SCANLINE, &partidx)); EXRCORE_TEST (partidx == 0); + { + uint64_t chunk_table_offset = 0; + int count = 0; + EXRCORE_TEST_RVAL ( + exr_get_chunk_table_offset (outf, 0, &chunk_table_offset)); + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, + exr_get_chunk_table_offset (outf, 0, NULL)); + EXRCORE_TEST_RVAL (exr_get_count (outf, &count)); + EXRCORE_TEST (count == 1); + } /* dup name check */ EXRCORE_TEST_RVAL_FAIL ( EXR_ERR_INVALID_ARGUMENT, From 545c9a782e34ce73d5f0ce8f3c45d5ea54a5ec98 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Wed, 17 Jun 2026 18:00:21 -0700 Subject: [PATCH 11/63] Split macOS wheel arches across CI runners (#2479) Both macOS matrix jobs previously built x86_64, arm64, and universal2, producing duplicate wheel filenames. Prior to #2433, the workflow downloaded each built wheel in succession, which would cause the duplicate wheel to overwrite the original, but it avoided an error. The new merge-multiple in the publish job corrupt the files, causing TestPyPI uploads to fail with "Mis-matched data size". This change builds x86_64 and universal2 on macos-15-intel and arm64 on macos-latest so merged artifacts have unique names. This also adds a validation step to the python-wheels.yml workflow to ensure the wheels have the expected structure. Signed-off-by: Cary Phillips --- .../workflows/python-wheels-publish-test.yml | 5 +- .github/workflows/python-wheels-publish.yml | 5 +- .github/workflows/python-wheels.yml | 63 ++++++++++++++++++- 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/.github/workflows/python-wheels-publish-test.yml b/.github/workflows/python-wheels-publish-test.yml index d321b8c43..93b2e496f 100644 --- a/.github/workflows/python-wheels-publish-test.yml +++ b/.github/workflows/python-wheels-publish-test.yml @@ -64,8 +64,10 @@ jobs: arch: arm64 - os: macos-15-intel arch: x64 + cibw_archs_macos: x86_64 universal2 - os: macos-latest arch: arm64 + cibw_archs_macos: arm64 - os: windows-latest arch: x64 @@ -96,7 +98,8 @@ jobs: output-dir: wheelhouse env: MACOSX_DEPLOYMENT_TARGET: 10.15 - CIBW_ARCHS_MACOS: x86_64 arm64 universal2 + # Split macOS arches across runners so artifact merge does not collide on filenames. + CIBW_ARCHS_MACOS: ${{ matrix.cibw_archs_macos }} # Build Python 3.9 through 3.13. # Skip 32-bit wheels builds on Windows # Also skip the PyPy builds, since they fail the unit tests diff --git a/.github/workflows/python-wheels-publish.yml b/.github/workflows/python-wheels-publish.yml index d4719eeb5..0be8ca76c 100644 --- a/.github/workflows/python-wheels-publish.yml +++ b/.github/workflows/python-wheels-publish.yml @@ -60,8 +60,10 @@ jobs: arch: arm64 - os: macos-15-intel arch: x64 + cibw_archs_macos: x86_64 universal2 - os: macos-latest arch: arm64 + cibw_archs_macos: arm64 - os: windows-latest arch: x64 @@ -90,7 +92,8 @@ jobs: output-dir: wheelhouse env: MACOSX_DEPLOYMENT_TARGET: 10.15 - CIBW_ARCHS_MACOS: x86_64 arm64 universal2 + # Split macOS arches across runners so artifact merge does not collide on filenames. + CIBW_ARCHS_MACOS: ${{ matrix.cibw_archs_macos }} # Build Python 3.9 through 3.13 # Skip 32-bit wheels builds on Windows # Also skip the PyPy builds, since they fail the unit tests diff --git a/.github/workflows/python-wheels.yml b/.github/workflows/python-wheels.yml index ad0fda065..5bc6a6bdd 100644 --- a/.github/workflows/python-wheels.yml +++ b/.github/workflows/python-wheels.yml @@ -48,8 +48,10 @@ jobs: arch: arm64 - os: macos-15-intel arch: x64 + cibw_archs_macos: x86_64 universal2 - os: macos-latest arch: arm64 + cibw_archs_macos: arm64 - os: windows-latest arch: x64 @@ -77,7 +79,8 @@ jobs: with: output-dir: wheelhouse env: - CIBW_ARCHS_MACOS: x86_64 arm64 universal2 + # Split macOS arches across runners so artifact merge does not collide on filenames. + CIBW_ARCHS_MACOS: ${{ matrix.cibw_archs_macos }} # Build Python 3.9 through 3.13 # Skip 32-bit wheels builds on Windows # Also skip the PyPy builds, since they fail the unit tests @@ -91,3 +94,61 @@ jobs: path: | ./wheelhouse/*.whl ./wheelhouse/*.tar.gz + + verify_publish_artifacts: + name: Verify merged wheel artifacts + needs: build_wheels + runs-on: ubuntu-latest + + permissions: + contents: read + actions: read + + steps: + - name: Download wheel artifacts separately + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: wheels-* + path: artifacts + + - name: Detect duplicate distribution filenames + run: | + set -euo pipefail + + mapfile -t dupes < <( + find artifacts -type f \( -name '*.whl' -o -name '*.tar.gz' \) -exec basename {} \; \ + | sort \ + | uniq -d + ) + + if ((${#dupes[@]} > 0)); then + echo "::error::Duplicate distribution filenames across build artifacts:" + printf ' %s\n' "${dupes[@]}" + exit 1 + fi + + - name: Download wheel artifacts (as publish does) + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: wheels-* + merge-multiple: true + path: dist + + - name: Verify wheel ZIP integrity + run: | + set -euo pipefail + shopt -s nullglob + + wheels=(dist/*.whl) + if ((${#wheels[@]} == 0)); then + echo "::error::No wheels found in dist/" + exit 1 + fi + + for wheel in "${wheels[@]}"; do + echo "Checking $wheel" + python3 -m zipfile -t "$wheel" + done + + - name: Validate distribution metadata + run: pipx run twine==6.1.0 check dist/* From 71bcf5cf44e124acce30bdd85056d6a025f80722 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Sat, 20 Jun 2026 18:57:59 -0700 Subject: [PATCH 12/63] Fix CI-old workflow failure due to Node 24 on old VFX platform containers (#2483) GitHub Actions deprecated Node 20 and now forces Node 24 by default, which requires glibc >= 2.25. The VFX 2021/2022 containers are CentOS 7 (glibc 2.17) and can't run Node 24, breaking the checkout step. Set ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true to allow the runner to use the Node 20 glibc-2.17 build installed in /node20217, which is the existing workaround for these old containers. Signed-off-by: Cary Phillips Co-authored-by: Claude Sonnet 4.6 --- .github/workflows/ci_workflow_old.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci_workflow_old.yml b/.github/workflows/ci_workflow_old.yml index 1d5c695c6..36602d3eb 100644 --- a/.github/workflows/ci_workflow_old.yml +++ b/.github/workflows/ci_workflow_old.yml @@ -64,6 +64,9 @@ jobs: - /node20217:/node20217:rw,rshared - /node20217:/__e/node20:ro,rshared + env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + strategy: matrix: include: From d7d4158694ce9251975f7ae9e8d08be5eae8fbb7 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Sun, 21 Jun 2026 14:39:05 -0700 Subject: [PATCH 13/63] Reject negative pixelDataSize in rawPixelDataToBuffer() (#2490) A negative int cast to uint64_t bypassed the buffer size check and allowed exr_read_chunk() to write past a caller buffer. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-gjpj-qv64-vwhf Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXR/ImfScanLineInputFile.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/OpenEXR/ImfScanLineInputFile.cpp b/src/lib/OpenEXR/ImfScanLineInputFile.cpp index d09f76b3a..20790fae4 100644 --- a/src/lib/OpenEXR/ImfScanLineInputFile.cpp +++ b/src/lib/OpenEXR/ImfScanLineInputFile.cpp @@ -361,7 +361,8 @@ ScanLineInputFile::rawPixelDataToBuffer ( if (EXR_ERR_SUCCESS == exr_read_scanline_chunk_info ( _ctxt, _data->partNumber, scanLine, &cinfo)) { - if (cinfo.packed_size > static_cast (pixelDataSize)) + if (pixelDataSize < 0 || + cinfo.packed_size > static_cast (pixelDataSize)) { THROW ( IEX_NAMESPACE::ArgExc, From 1d5882b07a2a58e30d2ee9f9b3317f783ad7a103 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Sun, 21 Jun 2026 14:39:47 -0700 Subject: [PATCH 14/63] Fix OpenEXRUtil row() OOB read with non-zero data window origin (#2488) The row() method in TypedDeepImageChannel, TypedFlatImageChannel, and SampleCountChannel is documented as 0-based within the data window, but used the _base offset meant for absolute (x, y) access. Index the compact backing arrays instead so row(0) aliases the first pixel when dataWindow.min is non-zero. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-hwmv-39v6-739m Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXRUtil/ImfDeepImageChannel.h | 4 +-- src/lib/OpenEXRUtil/ImfFlatImageChannel.h | 4 +-- src/lib/OpenEXRUtil/ImfSampleCountChannel.h | 2 +- src/test/OpenEXRUtilTest/testDeepImage.cpp | 34 +++++++++++++++++++++ 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/lib/OpenEXRUtil/ImfDeepImageChannel.h b/src/lib/OpenEXRUtil/ImfDeepImageChannel.h index 9096cfebc..0cacff7e6 100644 --- a/src/lib/OpenEXRUtil/ImfDeepImageChannel.h +++ b/src/lib/OpenEXRUtil/ImfDeepImageChannel.h @@ -248,14 +248,14 @@ template inline T* const* TypedDeepImageChannel::row (int r) { - return _base + r * pixelsPerRow (); + return _sampleListPointers + r * pixelsPerRow (); } template inline const T* const* TypedDeepImageChannel::row (int r) const { - return _base + r * pixelsPerRow (); + return _sampleListPointers + r * pixelsPerRow (); } #ifndef COMPILING_IMF_DEEP_IMAGE_CHANNEL diff --git a/src/lib/OpenEXRUtil/ImfFlatImageChannel.h b/src/lib/OpenEXRUtil/ImfFlatImageChannel.h index 032898506..01f348aa0 100644 --- a/src/lib/OpenEXRUtil/ImfFlatImageChannel.h +++ b/src/lib/OpenEXRUtil/ImfFlatImageChannel.h @@ -199,14 +199,14 @@ template inline T* TypedFlatImageChannel::row (int r) { - return _base + r * pixelsPerRow (); + return _pixels + r * pixelsPerRow (); } template inline const T* TypedFlatImageChannel::row (int n) const { - return _base + n * pixelsPerRow (); + return _pixels + n * pixelsPerRow (); } #ifndef COMPILING_IMF_FLAT_IMAGE_CHANNEL diff --git a/src/lib/OpenEXRUtil/ImfSampleCountChannel.h b/src/lib/OpenEXRUtil/ImfSampleCountChannel.h index d070b3e80..0d51284ee 100644 --- a/src/lib/OpenEXRUtil/ImfSampleCountChannel.h +++ b/src/lib/OpenEXRUtil/ImfSampleCountChannel.h @@ -316,7 +316,7 @@ SampleCountChannel::at (int x, int y) const inline const unsigned int* SampleCountChannel::row (int n) const { - return _base + n * pixelsPerRow (); + return _numSamples + n * pixelsPerRow (); } OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT diff --git a/src/test/OpenEXRUtilTest/testDeepImage.cpp b/src/test/OpenEXRUtilTest/testDeepImage.cpp index 6f48aef86..0b16fd23e 100644 --- a/src/test/OpenEXRUtilTest/testDeepImage.cpp +++ b/src/test/OpenEXRUtilTest/testDeepImage.cpp @@ -478,6 +478,39 @@ testSetSampleCountRowOffset () assert (sc.at (1, 1) == 1); } +void +testDeepChannelRowOffset () +{ + // + // Regression test for GHSA-hwmv-39v6-739m: row() is 0-based relative + // to the data window and must not use the _base pointer offset. + // + + cout << "deep channel row() with non-zero data window origin" << endl; + + DeepImage img; + img.insertChannel ("Z", FLOAT, 1, 1, false); + + const Box2i dataWindow (V2i (1024, -1024), V2i (1031, -1017)); + img.resize (dataWindow, ONE_LEVEL, ROUND_DOWN); + + DeepImageLevel& level = img.level (0); + TypedDeepImageChannel& channel = level.typedChannel ("Z"); + SampleCountChannel& sc = level.sampleCounts (); + + assert (channel.row (0)[0] == + channel.at (dataWindow.min.x, dataWindow.min.y)); + assert (&sc.row (0)[0] == &sc.at (dataWindow.min.x, dataWindow.min.y)); + + const int lastRow = channel.pixelsPerColumn () - 1; + const int lastCol = channel.pixelsPerRow () - 1; + + assert (channel.row (lastRow)[lastCol] == + channel.at (dataWindow.max.x, dataWindow.max.y)); + assert (&sc.row (lastRow)[lastCol] == + &sc.at (dataWindow.max.x, dataWindow.max.y)); +} + void testShiftPixels () { @@ -752,6 +785,7 @@ testDeepImage (const string& tempDir) testTiledImages (tempDir + "deepTiles.exr"); testSetSampleCounts (); testSetSampleCountRowOffset (); + testDeepChannelRowOffset (); testRoundListSizeUpLimits (); testShiftPixels (); testCropping (tempDir + "deepCropped.exr"); From 4eaf1a9f34f438a281e66b9f350b93018791aaeb Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Sun, 21 Jun 2026 14:40:22 -0700 Subject: [PATCH 15/63] Fix deep pixelmode heap buffer overflow in exrmetrics (#2487) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When --pixelmode float (or --bench) is used, outHeader channels are rewritten from the input type (e.g. HALF) to FLOAT. The DeepSlice framebuffer entries were already built from outHeader, requesting 4-byte FLOAT writes. However, the sample data buffers were allocated using the *input* header's channel types (2 bytes for HALF), so readPixels() wrote 4-byte values into 2-byte buffers — a heap buffer overflow. Fix: allocate sampleData using outHeader.channels() (the output/requested type) so that buffer sizes match the per-sample write size. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-6jj8-cxcr-j8hm Signed-off-by: Cary Phillips Co-authored-by: Claude Sonnet 4.6 --- src/bin/exrmetrics/exrmetrics.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/exrmetrics/exrmetrics.cpp b/src/bin/exrmetrics/exrmetrics.cpp index 42d31a58f..f1f1da178 100644 --- a/src/bin/exrmetrics/exrmetrics.cpp +++ b/src/bin/exrmetrics/exrmetrics.cpp @@ -379,8 +379,8 @@ initAndReadDeepScanLine ( sampleData.resize (numChans); channelNumber = 0; - for (ChannelList::ConstIterator i = in.header ().channels ().begin (); - i != in.header ().channels ().end (); + for (ChannelList::ConstIterator i = outHeader.channels ().begin (); + i != outHeader.channels ().end (); ++i) { int samplesize = pixelTypeSize (i.channel ().type); From 492edbfcadce78331fa49f6d4f720e74a70316b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 06:22:35 -0700 Subject: [PATCH 16/63] Bump vmactions/freebsd-vm from 1.4.6 to 1.4.8 (#2495) Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm) from 1.4.6 to 1.4.8. - [Release notes](https://github.com/vmactions/freebsd-vm/releases) - [Commits](https://github.com/vmactions/freebsd-vm/compare/a6de9343ef5747433d9c25784c90e84998b9d69a...b84ab5559b5a1bb4b8ee2737d2506a16e1737636) --- updated-dependencies: - dependency-name: vmactions/freebsd-vm dependency-version: 1.4.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci_freebsd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_freebsd.yml b/.github/workflows/ci_freebsd.yml index 43cdd46e9..f44bb814b 100644 --- a/.github/workflows/ci_freebsd.yml +++ b/.github/workflows/ci_freebsd.yml @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Build and test on FreeBSD - uses: vmactions/freebsd-vm@a6de9343ef5747433d9c25784c90e84998b9d69a # v1.4.6 + uses: vmactions/freebsd-vm@b84ab5559b5a1bb4b8ee2737d2506a16e1737636 # v1.4.8 with: release: '15.0' envs: GITHUB_REPOSITORY GITHUB_REF GITHUB_SHA From d4c767c86bc965ca7834ee744cb51c7eb5194561 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 22 Jun 2026 06:23:09 -0700 Subject: [PATCH 17/63] Reject oversized DWAA buffer allocations on ILP32 (#2494) Check packed AC/DC and RLE buffer sizes against SIZE_MAX before calling alloc_fn(size_t). Without this, uint64_t sizes above 4 GiB truncate on 32-bit builds while later DWAA decode logic still uses the full size, leading to heap corruption during AC inflate. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-6662-fq6f-93mp Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXRCore/internal_dwa_compressor.h | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/lib/OpenEXRCore/internal_dwa_compressor.h b/src/lib/OpenEXRCore/internal_dwa_compressor.h index 88ec309dc..e9b712352 100644 --- a/src/lib/OpenEXRCore/internal_dwa_compressor.h +++ b/src/lib/OpenEXRCore/internal_dwa_compressor.h @@ -1403,10 +1403,15 @@ DwaCompressor_initializeBuffers (DwaCompressor* me, size_t* bufferSize) if (maxLossyDctAcSize * numLossyDctChans > me->_packedAcBufferSize) { me->_packedAcBufferSize = maxLossyDctAcSize * numLossyDctChans; + if (me->_packedAcBufferSize > SIZE_MAX) + { + return EXR_ERR_OUT_OF_MEMORY; + } + if (me->_packedAcBuffer != NULL) me->free_fn (me->_packedAcBuffer); - me->_packedAcBuffer = me->alloc_fn (me->_packedAcBufferSize); + me->_packedAcBuffer = me->alloc_fn ((size_t) me->_packedAcBufferSize); if (!me->_packedAcBuffer) return EXR_ERR_OUT_OF_MEMORY; - memset (me->_packedAcBuffer, 0, me->_packedAcBufferSize); + memset (me->_packedAcBuffer, 0, (size_t) me->_packedAcBufferSize); } // @@ -1416,19 +1421,29 @@ DwaCompressor_initializeBuffers (DwaCompressor* me, size_t* bufferSize) if (maxLossyDctDcSize * numLossyDctChans > me->_packedDcBufferSize) { me->_packedDcBufferSize = maxLossyDctDcSize * numLossyDctChans; + if (me->_packedDcBufferSize > SIZE_MAX) + { + return EXR_ERR_OUT_OF_MEMORY; + } + if (me->_packedDcBuffer != NULL) me->free_fn (me->_packedDcBuffer); - me->_packedDcBuffer = me->alloc_fn (me->_packedDcBufferSize); + me->_packedDcBuffer = me->alloc_fn ((size_t) me->_packedDcBufferSize); if (!me->_packedDcBuffer) return EXR_ERR_OUT_OF_MEMORY; - memset (me->_packedDcBuffer, 0, me->_packedDcBufferSize); + memset (me->_packedDcBuffer, 0, (size_t) me->_packedDcBufferSize); } if (rleBufferSize > me->_rleBufferSize) { me->_rleBufferSize = rleBufferSize; + if (rleBufferSize > SIZE_MAX) + { + return EXR_ERR_OUT_OF_MEMORY; + } + if (me->_rleBuffer != 0) me->free_fn (me->_rleBuffer); - me->_rleBuffer = me->alloc_fn (rleBufferSize); + me->_rleBuffer = me->alloc_fn ((size_t) rleBufferSize); if (!me->_rleBuffer) return EXR_ERR_OUT_OF_MEMORY; - memset (me->_rleBuffer, 0, rleBufferSize); + memset (me->_rleBuffer, 0, (size_t) rleBufferSize); } // From b78496b324832e7cb1ff6b64373a3fe1cfa84e70 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 22 Jun 2026 06:23:43 -0700 Subject: [PATCH 18/63] Fix ILP32 unpacked buffer size truncation in RLE decode (#2493) In update_pack_unpack_ptrs(), decode->chunk.unpacked_size is uint64_t but was passed directly to internal_decode_alloc_buffer() which takes size_t. On ILP32 builds a crafted chunk with unpacked_size > 4 GiB silently truncates, allocating a tiny buffer while the decompressor and unpacker iterate over the full declared channel width, causing an out-of-bounds read. Add a truncation check before the allocation and return EXR_ERR_OUT_OF_MEMORY if unpacked_size exceeds SIZE_MAX. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-v6v5-344m-64vm Signed-off-by: Cary Phillips Co-authored-by: Claude Sonnet 4.6 --- src/lib/OpenEXRCore/decoding.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/OpenEXRCore/decoding.c b/src/lib/OpenEXRCore/decoding.c index 0ca2a9980..9bf3ef1e7 100644 --- a/src/lib/OpenEXRCore/decoding.c +++ b/src/lib/OpenEXRCore/decoding.c @@ -72,12 +72,14 @@ update_pack_unpack_ptrs (exr_decode_pipeline_t* decode) } else { + if (decode->chunk.unpacked_size != (size_t) decode->chunk.unpacked_size) + return EXR_ERR_OUT_OF_MEMORY; rv = internal_decode_alloc_buffer ( decode, EXR_TRANSCODE_BUFFER_UNPACKED, &(decode->unpacked_buffer), &(decode->unpacked_alloc_size), - decode->chunk.unpacked_size); + (size_t) decode->chunk.unpacked_size); } return rv; From 9ae8905b001a30353a294032507366e8bbeb0fdc Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 22 Jun 2026 06:25:03 -0700 Subject: [PATCH 19/63] Fix signed integer overflow in unpack_sample_table() (#2484) * Fix signed integer overflow in unpack_sample_table() Declare w and h as int64_t instead of int32_t so that index arithmetic y*w and w*h in unpack_sample_table() does not overflow when tile dimensions are large (e.g. 46342x46342). Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-rqp5-pmwm-wj6x Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Cary Phillips * declare y as int64_t Signed-off-by: Cary Phillips --------- Signed-off-by: Cary Phillips Co-authored-by: Claude Sonnet 4.6 --- src/lib/OpenEXRCore/decoding.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/OpenEXRCore/decoding.c b/src/lib/OpenEXRCore/decoding.c index 9bf3ef1e7..51bf329e7 100644 --- a/src/lib/OpenEXRCore/decoding.c +++ b/src/lib/OpenEXRCore/decoding.c @@ -217,8 +217,8 @@ static exr_result_t unpack_sample_table (exr_const_context_t ctxt, exr_decode_pipeline_t* decode) { exr_result_t rv = EXR_ERR_SUCCESS; - int32_t w = decode->chunk.width; - int32_t h = decode->chunk.height; + int64_t w = decode->chunk.width; + int64_t h = decode->chunk.height; uint64_t totsamp = 0; int32_t* samptable = decode->sample_count_table; size_t combSampSize = 0; @@ -228,7 +228,7 @@ unpack_sample_table (exr_const_context_t ctxt, exr_decode_pipeline_t* decode) if ((decode->decode_flags & EXR_DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL)) { - for (int32_t y = 0; y < h; ++y) + for (int64_t y = 0; y < h; ++y) { int32_t* cursampline = samptable + y * w; int32_t prevsamp = 0; @@ -248,7 +248,7 @@ unpack_sample_table (exr_const_context_t ctxt, exr_decode_pipeline_t* decode) } else { - for (int32_t y = 0; y < h; ++y) + for (int64_t y = 0; y < h; ++y) { int32_t* cursampline = samptable + y * w; int32_t prevsamp = 0; From d66348eaa345311735049f58efdd836573ef6eab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 06:26:51 -0700 Subject: [PATCH 20/63] Bump actions/checkout from 6.0.3 to 7.0.0 (#2481) Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/df4cb1c069e1874edd31b4311f1884172cec0e10...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/analysis_workflow.yml | 6 +++--- .github/workflows/bazel_build.yml | 6 +++--- .github/workflows/ci_steps.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/python-wheels-publish-test.yml | 4 ++-- .github/workflows/python-wheels-publish.yml | 4 ++-- .github/workflows/python-wheels.yml | 2 +- .github/workflows/release-sign.yml | 2 +- .github/workflows/scorecard.yml | 2 +- .github/workflows/snyk-scan-cron.yml | 2 +- .github/workflows/website.yml | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/analysis_workflow.yml b/.github/workflows/analysis_workflow.yml index 83297a152..74afface2 100644 --- a/.github/workflows/analysis_workflow.yml +++ b/.github/workflows/analysis_workflow.yml @@ -35,7 +35,7 @@ jobs: CC: gcc steps: - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 50 - name: Create build directories @@ -105,7 +105,7 @@ jobs: - name: Setup container run: sudo rm -rf /usr/local/lib64/cmake/glew - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 50 - name: Create build directories @@ -184,7 +184,7 @@ jobs: - name: Setup container run: sudo rm -rf /usr/local/lib64/cmake/glew - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 50 - name: Create build directories diff --git a/.github/workflows/bazel_build.yml b/.github/workflows/bazel_build.yml index c0090c1e0..caa5b21ab 100644 --- a/.github/workflows/bazel_build.yml +++ b/.github/workflows/bazel_build.yml @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Mount Bazel cache uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 @@ -57,7 +57,7 @@ jobs: runs-on: windows-2025 steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Mount Bazel cache uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 @@ -75,7 +75,7 @@ jobs: runs-on: macos-15 steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Mount Bazel cache uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 diff --git a/.github/workflows/ci_steps.yml b/.github/workflows/ci_steps.yml index 4a20ec73c..cd491e841 100644 --- a/.github/workflows/ci_steps.yml +++ b/.github/workflows/ci_steps.yml @@ -88,7 +88,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Set Up Directories & Environment run: | diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b945e9312..49eea6588 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -61,7 +61,7 @@ jobs: # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/python-wheels-publish-test.yml b/.github/workflows/python-wheels-publish-test.yml index 93b2e496f..eba5cf512 100644 --- a/.github/workflows/python-wheels-publish-test.yml +++ b/.github/workflows/python-wheels-publish-test.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 ref: ${{ github.ref }} @@ -77,7 +77,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} diff --git a/.github/workflows/python-wheels-publish.yml b/.github/workflows/python-wheels-publish.yml index 0be8ca76c..cd940d098 100644 --- a/.github/workflows/python-wheels-publish.yml +++ b/.github/workflows/python-wheels-publish.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 ref: ${{ github.event_name == 'release' && github.event.release.tag_name || github.ref }} @@ -73,7 +73,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} diff --git a/.github/workflows/python-wheels.yml b/.github/workflows/python-wheels.yml index 5bc6a6bdd..c513b5056 100644 --- a/.github/workflows/python-wheels.yml +++ b/.github/workflows/python-wheels.yml @@ -61,7 +61,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} diff --git a/.github/workflows/release-sign.yml b/.github/workflows/release-sign.yml index f0cc50820..a24953d6f 100644 --- a/.github/workflows/release-sign.yml +++ b/.github/workflows/release-sign.yml @@ -55,7 +55,7 @@ jobs: shell: bash - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index ee124e06e..fd72fa70d 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -28,7 +28,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/snyk-scan-cron.yml b/.github/workflows/snyk-scan-cron.yml index 9b53cfadb..513e1bb70 100644 --- a/.github/workflows/snyk-scan-cron.yml +++ b/.github/workflows/snyk-scan-cron.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'AcademySoftwareFoundation/openexr' steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: snyk/actions/setup@9adf32b1121593767fc3c057af55b55db032dc04 # v1.0.0 id: snyk diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index edc8877f5..20611035f 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -54,7 +54,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Create build directory run: mkdir _build - name: Install doxygen From 592a1eecf6b9b57a7f3d2a373967764ee633c9f0 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 22 Jun 2026 17:47:47 -0700 Subject: [PATCH 21/63] Fix ILP32 deep sample-count table size overflow in decoding (#2492) In update_pack_unpack_ptrs(), sampsize was computed as size_t, so on ILP32 builds a tile with width*height >= 2^30 wraps to zero (or four with the INDIVIDUAL flag), causing the sample-count table to be allocated too small and unpack_sample_table() to read far past it. Compute the size in uint64_t, check for truncation before converting to size_t, and return EXR_ERR_OUT_OF_MEMORY if the required size exceeds SIZE_MAX. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-p42q-g5c9-mh9w Signed-off-by: Cary Phillips Co-authored-by: Claude Sonnet 4.6 --- src/lib/OpenEXRCore/decoding.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/OpenEXRCore/decoding.c b/src/lib/OpenEXRCore/decoding.c index 51bf329e7..d92cab1f4 100644 --- a/src/lib/OpenEXRCore/decoding.c +++ b/src/lib/OpenEXRCore/decoding.c @@ -26,12 +26,14 @@ update_pack_unpack_ptrs (exr_decode_pipeline_t* decode) if (stortype == EXR_STORAGE_DEEP_SCANLINE || stortype == EXR_STORAGE_DEEP_TILED) { - size_t sampsize = - (((size_t) decode->chunk.width) * ((size_t) decode->chunk.height)); + uint64_t sampsize64 = + ((uint64_t) decode->chunk.width) * ((uint64_t) decode->chunk.height); if ((decode->decode_flags & EXR_DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL)) - sampsize += 1; - sampsize *= sizeof (int32_t); + sampsize64 += 1; + sampsize64 *= sizeof (int32_t); + if (sampsize64 != (size_t) sampsize64) return EXR_ERR_OUT_OF_MEMORY; + size_t sampsize = (size_t) sampsize64; if (decode->chunk.sample_count_table_size == sampsize) { From b216124e53f604f0c39e471b0296a1bd981dfdc8 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 22 Jun 2026 17:48:16 -0700 Subject: [PATCH 22/63] Fix empty multiView crash in viewFromChannelName() (#2496) Dotless channel names used multiView[0] without checking for an empty vector. Use defaultViewName() so malformed files return "" instead of OOB access. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-g8f2-r72m-48vx Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXR/ImfMultiView.cpp | 2 +- src/test/OpenEXRTest/testMultiView.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib/OpenEXR/ImfMultiView.cpp b/src/lib/OpenEXR/ImfMultiView.cpp index 34397b4f7..0df68f788 100644 --- a/src/lib/OpenEXR/ImfMultiView.cpp +++ b/src/lib/OpenEXR/ImfMultiView.cpp @@ -118,7 +118,7 @@ viewFromChannelName (const string& channel, const StringVector& multiView) // in the name belong to the default view. // - return multiView[0]; + return defaultViewName (multiView); } else { diff --git a/src/test/OpenEXRTest/testMultiView.cpp b/src/test/OpenEXRTest/testMultiView.cpp index 47097041a..d5d422485 100644 --- a/src/test/OpenEXRTest/testMultiView.cpp +++ b/src/test/OpenEXRTest/testMultiView.cpp @@ -110,6 +110,13 @@ testMultiViewFunctions () assert ( viewFromChannelName ("devon.and.cornwall.longwool", multiView) == ""); + // + // Regression test for GHSA-g8f2-r72m-48vx: empty multiView must not + // index element 0; dotless channels belong to no named view. + // + + assert (viewFromChannelName ("R", StringVector ()) == ""); + // // Test areCounterparts() // From 8ce07f00fd540afb7a4b70b37aa2b0d1424c1535 Mon Sep 17 00:00:00 2001 From: peterhillman Date: Tue, 23 Jun 2026 14:49:21 +1200 Subject: [PATCH 23/63] Avoid memory allocation in idmanifest parsing (#2498) * Avoid memory allocation in idmanifest parsing Signed-off-by: Peter Hillman * check for negative string count, fix table size count Signed-off-by: Peter Hillman --------- Signed-off-by: Peter Hillman Co-authored-by: Cary Phillips --- src/lib/OpenEXR/ImfIDManifest.cpp | 42 +++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/lib/OpenEXR/ImfIDManifest.cpp b/src/lib/OpenEXR/ImfIDManifest.cpp index 591f4d372..9a3527fe9 100644 --- a/src/lib/OpenEXR/ImfIDManifest.cpp +++ b/src/lib/OpenEXR/ImfIDManifest.cpp @@ -177,21 +177,53 @@ readStringList ( Xdr::read (readPtr, numberOfStrings); } - vector lengths (numberOfStrings); + + if (numberOfStrings < 0) + { + throw IEX_NAMESPACE::InputExc ( + "Negative count for number of strings"); + } + + if (readPtr + numberOfStrings > endPtr) + { + throw IEX_NAMESPACE::InputExc ( + "IDManifest too small for string length table"); + } + + + // + // compute total table size + // + const char* tablePtr = readPtr; + + size_t totalTableSize = 0; for (int i = 0; i < numberOfStrings; ++i) { - lengths[i] = readVariableLengthInteger (readPtr, endPtr); + totalTableSize += readVariableLengthInteger (readPtr, endPtr); + } + + + if(readPtr + totalTableSize > endPtr) + { + throw IEX_NAMESPACE::InputExc ("IDManifest too small for string table"); } + + // + // now tablePtr points to size of string in string table, and readPtr + // points to the string itself + // + for (int i = 0; i < numberOfStrings; ++i) { - if (readPtr + lengths[i] > endPtr) + size_t length = readVariableLengthInteger (tablePtr, endPtr); + if (readPtr + length > endPtr) { throw IEX_NAMESPACE::InputExc ("IDManifest too small for string"); } - outputVector.insert (outputVector.end (), string (readPtr, lengths[i])); - readPtr += lengths[i]; + outputVector.insert (outputVector.end (), string (readPtr, length)); + readPtr += length; } } From d9de1caaa6982478fb3180b19cb95fbed1b4a3d7 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 22 Jun 2026 20:36:19 -0700 Subject: [PATCH 24/63] Fix integer overflow in Array2D::resizeErase() on ILP32/LLP64 builds (#2486) * Fix integer overflow in Array2D::resizeErase() on ILP32/LLP64 builds sizeX * sizeY used long arithmetic, which is 32 bits on ILP32 (32-bit Linux) and on Windows (MSVC LLP64). A tile size of 65537x65537 overflows to a small positive value, causing new[] to under-allocate and subsequent tile decoding to write past the buffer. Cast both operands to size_t before multiplying so the allocation is always correct regardless of the width of long. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-f667-c4wm-c8gq Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Cary Phillips * validate non-negative sizes Signed-off-by: Cary Phillips --------- Signed-off-by: Cary Phillips Co-authored-by: Claude Sonnet 4.6 --- src/lib/OpenEXR/ImfArray.h | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/lib/OpenEXR/ImfArray.h b/src/lib/OpenEXR/ImfArray.h index 211d818e3..395fc67e5 100644 --- a/src/lib/OpenEXR/ImfArray.h +++ b/src/lib/OpenEXR/ImfArray.h @@ -7,6 +7,9 @@ #define INCLUDED_IMF_ARRAY_H #include "ImfForward.h" +#include "IexBaseExc.h" + +#include //------------------------------------------------------------------------- // @@ -54,8 +57,11 @@ template class IMF_EXPORT_TEMPLATE_TYPE Array _data = 0; _size = 0; } - Array (long size) + Array (long size) : _size (0), _data (0) { + if (size < 0) + throw IEX_NAMESPACE::ArgExc ("Array size must be non-negative"); + _data = new T[size]; _size = size; } @@ -158,6 +164,9 @@ template inline void Array::resizeErase (long size) { + if (size < 0) + throw IEX_NAMESPACE::ArgExc ("Array size must be non-negative"); + T* tmp = new T[size]; delete[] _data; _size = size; @@ -168,6 +177,9 @@ template inline void Array::resizeEraseUnsafe (long size) { + if (size < 0) + throw IEX_NAMESPACE::ArgExc ("Array size must be non-negative"); + delete[] _data; _data = 0; _size = 0; @@ -183,9 +195,14 @@ inline Array2D::Array2D () : _sizeX (0), _sizeY (0), _data (0) template inline Array2D::Array2D (long sizeX, long sizeY) - : _sizeX (sizeX), _sizeY (sizeY), _data (new T[sizeX * sizeY]) + : _sizeX (0), _sizeY (0), _data (0) { - // empty + if (sizeX < 0 || sizeY < 0) + throw IEX_NAMESPACE::ArgExc ("Array2D dimensions must be non-negative"); + + _sizeX = sizeX; + _sizeY = sizeY; + _data = new T[(size_t) sizeX * (size_t) sizeY]; } template inline Array2D::~Array2D () @@ -211,7 +228,10 @@ template inline void Array2D::resizeErase (long sizeX, long sizeY) { - T* tmp = new T[sizeX * sizeY]; + if (sizeX < 0 || sizeY < 0) + throw IEX_NAMESPACE::ArgExc ("Array2D dimensions must be non-negative"); + + T* tmp = new T[(size_t) sizeX * (size_t) sizeY]; delete[] _data; _sizeX = sizeX; _sizeY = sizeY; @@ -222,11 +242,14 @@ template inline void Array2D::resizeEraseUnsafe (long sizeX, long sizeY) { + if (sizeX < 0 || sizeY < 0) + throw IEX_NAMESPACE::ArgExc ("Array2D dimensions must be non-negative"); + delete[] _data; _data = 0; _sizeX = 0; _sizeY = 0; - _data = new T[sizeX * sizeY]; + _data = new T[(size_t) sizeX * (size_t) sizeY]; _sizeX = sizeX; _sizeY = sizeY; } From 148400460f4700af87c6a9694222c54c8c6c80f7 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Tue, 23 Jun 2026 15:22:41 -0700 Subject: [PATCH 25/63] Reject NULL preview rgba data in exr_attr_set_preview() (#2469) Validate the source rgba pointer before memcpy in exr_attr_preview_create() and the same-dimensions update path in exr_attr_set_preview(), preventing a NULL pointer dereference when nonzero preview dimensions are supplied without pixel data. Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXRCore/part_attr.c | 6 +++++ src/lib/OpenEXRCore/preview.c | 18 +++++++++----- src/test/OpenEXRCoreTest/general_attr.cpp | 29 +++++++++++++++++++++++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/lib/OpenEXRCore/part_attr.c b/src/lib/OpenEXRCore/part_attr.c index bf528f589..e381fb0f9 100644 --- a/src/lib/OpenEXRCore/part_attr.c +++ b/src/lib/OpenEXRCore/part_attr.c @@ -1947,6 +1947,12 @@ exr_attr_set_preview ( { size_t copybytes = (size_t) val->width * (size_t) val->height * (size_t) 4; + if (copybytes > 0 && !val->rgba) + return EXR_UNLOCK_AND_RETURN (ctxt->print_error ( + ctxt, + EXR_ERR_INVALID_ARGUMENT, + "Invalid NULL preview rgba data for setting '%s'", + name)); memcpy ( EXR_CONST_CAST (void*, attr->preview->rgba), val->rgba, diff --git a/src/lib/OpenEXRCore/preview.c b/src/lib/OpenEXRCore/preview.c index 6648b3a2c..d171f48a7 100644 --- a/src/lib/OpenEXRCore/preview.c +++ b/src/lib/OpenEXRCore/preview.c @@ -59,13 +59,19 @@ exr_attr_preview_create ( uint32_t h, const uint8_t* d) { + size_t copybytes = (size_t) w * (size_t) h * (size_t) 4; + + if (copybytes > 0 && !d) + return ctxt->print_error ( + ctxt, + EXR_ERR_INVALID_ARGUMENT, + "Invalid NULL preview rgba data for %u x %u preview", + w, + h); + exr_result_t rv = exr_attr_preview_init (ctxt, p, w, h); - if (rv == EXR_ERR_SUCCESS) - { - size_t copybytes = w * h * 4; - if (copybytes > 0) - memcpy (EXR_CONST_CAST (uint8_t*, p->rgba), d, copybytes); - } + if (rv == EXR_ERR_SUCCESS && copybytes > 0) + memcpy (EXR_CONST_CAST (uint8_t*, p->rgba), d, copybytes); return rv; } diff --git a/src/test/OpenEXRCoreTest/general_attr.cpp b/src/test/OpenEXRCoreTest/general_attr.cpp index 78ff201d9..07a1ef286 100644 --- a/src/test/OpenEXRCoreTest/general_attr.cpp +++ b/src/test/OpenEXRCoreTest/general_attr.cpp @@ -848,6 +848,35 @@ testPreviewHelper (exr_context_t f) // make sure we can re-delete something? EXRCORE_TEST_RVAL (exr_attr_preview_destroy (f, &p)); + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, exr_attr_preview_create (f, &p, 1, 1, NULL)); + + { + exr_attr_preview_t preview; + preview.width = 1; + preview.height = 1; + preview.alloc_size = 0; + preview.rgba = NULL; + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, + exr_attr_set_preview (f, 0, "badPreview", &preview)); + } + + { + exr_attr_preview_t preview; + preview.width = 1; + preview.height = 1; + preview.alloc_size = 4; + preview.rgba = data1x1; + EXRCORE_TEST_RVAL ( + exr_attr_set_preview (f, 0, "goodPreview", &preview)); + + preview.rgba = NULL; + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, + exr_attr_set_preview (f, 0, "goodPreview", &preview)); + } + EXRCORE_TEST_RVAL_FAIL_MALLOC ( EXR_ERR_OUT_OF_MEMORY, exr_attr_preview_create (f, &p, 1, 1, data1x1)); } From 3f6e92b28ef2e36b1b85046f37a521864d29c295 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Tue, 23 Jun 2026 15:23:56 -0700 Subject: [PATCH 26/63] Reject NULL channel list entries in exr_attr_chlist_duplicate() (#2473) Validate num_channels > 0 with entries == NULL before pointer arithmetic, covering exr_set_channels() and exr_attr_set_channels(). Also, refactor exr_attr_set_channels to call exr_attr_chlist_duplicate() since it does the same work. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-mqmw-xv8w-5jh4 Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXRCore/channel_list.c | 7 ++++++ src/lib/OpenEXRCore/part_attr.c | 30 +---------------------- src/test/OpenEXRCoreTest/general_attr.cpp | 14 +++++++++++ 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/lib/OpenEXRCore/channel_list.c b/src/lib/OpenEXRCore/channel_list.c index bd0c2352a..61fc89acc 100644 --- a/src/lib/OpenEXRCore/channel_list.c +++ b/src/lib/OpenEXRCore/channel_list.c @@ -221,6 +221,13 @@ exr_attr_chlist_duplicate ( if (!chl || !srcchl) return EXR_ERR_INVALID_ARGUMENT; numchans = srcchl->num_channels; + if (numchans > 0 && !srcchl->entries) + return ctxt->print_error ( + ctxt, + EXR_ERR_INVALID_ARGUMENT, + "Invalid NULL channel list entries with %d channels", + numchans); + rv = exr_attr_chlist_init (ctxt, chl, numchans); if (rv != EXR_ERR_SUCCESS) return rv; diff --git a/src/lib/OpenEXRCore/part_attr.c b/src/lib/OpenEXRCore/part_attr.c index e381fb0f9..18ecd32ba 100644 --- a/src/lib/OpenEXRCore/part_attr.c +++ b/src/lib/OpenEXRCore/part_attr.c @@ -1433,38 +1433,10 @@ exr_attr_set_channels ( if (rv == EXR_ERR_SUCCESS) { exr_attr_chlist_t clist; - int numchans; - if (!channels) - return EXR_UNLOCK_AND_RETURN (ctxt->report_error ( - ctxt, - EXR_ERR_INVALID_ARGUMENT, - "No channels provided for channel list")); - - numchans = channels->num_channels; - rv = exr_attr_chlist_init (ctxt, &clist, numchans); + rv = exr_attr_chlist_duplicate (ctxt, &clist, channels); if (rv != EXR_ERR_SUCCESS) return EXR_UNLOCK_AND_RETURN (rv); - for (int c = 0; c < numchans; ++c) - { - const exr_attr_chlist_entry_t* cur = channels->entries + c; - - rv = exr_attr_chlist_add_with_length ( - ctxt, - &clist, - cur->name.str, - cur->name.length, - cur->pixel_type, - cur->p_linear, - cur->x_sampling, - cur->y_sampling); - if (rv != EXR_ERR_SUCCESS) - { - exr_attr_chlist_destroy (ctxt, &clist); - return EXR_UNLOCK_AND_RETURN (rv); - } - } - exr_attr_chlist_destroy (ctxt, attr->chlist); *(attr->chlist) = clist; } diff --git a/src/test/OpenEXRCoreTest/general_attr.cpp b/src/test/OpenEXRCoreTest/general_attr.cpp index 07a1ef286..c11be86f0 100644 --- a/src/test/OpenEXRCoreTest/general_attr.cpp +++ b/src/test/OpenEXRCoreTest/general_attr.cpp @@ -774,6 +774,20 @@ testChlistHelper (exr_context_t f) 1, EXR_ERR_OUT_OF_MEMORY, exr_attr_chlist_duplicate (f, &cl2, &cl)); EXRCORE_TEST_RVAL (exr_attr_chlist_destroy (f, &cl2)); + { + exr_attr_chlist_t bad = {0}; + bad.num_channels = 1; + bad.entries = NULL; + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, + exr_attr_chlist_duplicate (f, &cl2, &bad)); + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, exr_set_channels (f, 0, &bad)); + EXRCORE_TEST_RVAL_FAIL ( + EXR_ERR_INVALID_ARGUMENT, + exr_attr_set_channels (f, 0, "badChlist", &bad)); + } + /* without a file, max will be 31 */ EXRCORE_TEST_RVAL_FAIL ( EXR_ERR_NAME_TOO_LONG, From 6820342930d35c7c81a6b220c4a0aca9c2532542 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Tue, 23 Jun 2026 15:24:29 -0700 Subject: [PATCH 27/63] Fix Name::operator= to null-terminate long strings (#2500) Name::operator= leaves the string without a terminating null if the string is longer than MAX_LENGTH. Write a null to ensure there is one. Signed-off-by: Cary Phillips --- src/lib/OpenEXR/ImfName.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/OpenEXR/ImfName.h b/src/lib/OpenEXR/ImfName.h index 5d905c0d4..109dd6ff7 100644 --- a/src/lib/OpenEXR/ImfName.h +++ b/src/lib/OpenEXR/ImfName.h @@ -72,6 +72,7 @@ inline Name& Name::operator= (const char text[]) { strncpy (_text, text, MAX_LENGTH); + _text[MAX_LENGTH] = 0; return *this; } From 54aa30299cdf234ae0aaef804b252430527a8469 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Sun, 28 Jun 2026 20:13:45 -0700 Subject: [PATCH 28/63] Release notes and news for v3.4.13, v3.3.12, and v3.2.10 (#2497) * Changes for v3.14.13 Signed-off-by: Peter Hillman * update notes with additional PRs Signed-off-by: Cary Phillips * Add 2479 to notes Signed-off-by: Cary Phillips * fix duplicate 3.4.13 security references Signed-off-by: Cary Phillips * 3.4.13 news Signed-off-by: Cary Phillips * update changes for v3.3.12 Signed-off-by: Peter Hillman * update CHANGES for 3.2.10 Signed-off-by: Peter Hillman * news & notes for 3.3 and 3.2 Signed-off-by: Cary Phillips * fix links Signed-off-by: Cary Phillips --------- Signed-off-by: Peter Hillman Signed-off-by: Cary Phillips Co-authored-by: Peter Hillman --- CHANGES.md | 148 ++++++++++++++++++++++++++++++++++ website/latest_news_title.rst | 2 +- website/news.rst | 48 ++++++++++- 3 files changed, 195 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ca88cf465..ce2243477 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ # OpenEXR Release Notes +* [Version 3.4.13](#version-3413-june-19-2026) June 19, 2026 * [Version 3.4.12](#version-3412-may-24-2026) May 24, 2026 * [Version 3.4.11](#version-3411-april-29-2026) April 29, 2026 * [Version 3.4.10](#version-3410-april-17-2026) April 17, 2026 @@ -16,6 +17,7 @@ * [Version 3.4.2](#version-342-october-15-2025) October 15, 2025 * [Version 3.4.1](#version-341-october-8-2025) October 8, 2025 * [Version 3.4.0](#version-340-september-5-2025) September 5, 2025 +* [Version 3.3.12](#version-3312-june-21-2026) June 21, 2026 * [Version 3.3.11](#version-3311-april-29-2026) April 29, 2026 * [Version 3.3.10](#version-339-april-17-2026) April 17, 2026 * [Version 3.3.9](#version-339-april-4-2026) April 4, 2026 @@ -28,6 +30,7 @@ * [Version 3.3.2](#version-332-november-11-2024) November 11, 2024 * [Version 3.3.1](#version-331-october-8-2024) October 8, 2024 * [Version 3.3.0](#version-330-september-30-2024) September 30, 2024 +* [Version 3.2.10](#version-3210-june-21-2026) June 21, 2026 * [Version 3.2.9](#version-329-april-29-2026) April 29, 2026 * [Version 3.2.8](#version-328-april-17-2026) April 17, 2026 * [Version 3.2.7](#version-327-april-3-2026) April 3, 2026 @@ -104,6 +107,93 @@ * [Version 1.0.1](#version-101) * [Version 1.0](#version-10) +## Version 3.4.13 (June 19, 2026) + +Patch release that addresses several bugs and security +vulnerabilities. + +* :bug: Fix a regression introduced in v3.4.11 in decoding of DWAA compression +* :bug: Fix to handling deep images and very large images with the OpenEXRUtil library +* :bug: Fix initiliazation issue in B44A decoding +* :bug: Validate HTJ2K chunk header length before decode +* :hammer_and_wrench: Fix when building statically and using the vendored OpenJPH library + +For the python module: + +* :snake: :sparkles: Support NumPy scalar values Box2i and V2f tuple bindings + +This release addresses the following security vulnerabilities: + +* [CVE-2026-55373](https://www.cve.org/CVERecord?id=CVE-2026-55373) + OpenEXRUtil `SampleCountChannel` `endEdit()` can loop forever on `UINT_MAX` sample counts +* [CVE-2026-55371](https://www.cve.org/CVERecord?id=CVE-2026-55371) + OpenEXRCore `exr_attr_set_bytes()` accepts NULL `type_hint` with positive `hint_length` +* [CVE-2026-55059](https://www.cve.org/CVERecord?id=CVE-2026-55059) + OpenEXRUtil `SampleCountChannel` row setter heap out-of-bounds write +* [CVE-2026-54920](https://www.cve.org/CVERecord?id=CVE-2026-54920) + Integer Overflow and Use of Uninitialized Pointer leading to Invalid Delete in OpenEXRUtil Image Resize +* [CVE-2026-53532](https://www.cve.org/CVERecord?id=CVE-2026-53532) + Unhandled assert abort in HTJ2K decoder via crafted QCD marker (DoS) + +### Merged Pull Requests + +* [2476](https://github.com/AcademySoftwareFoundation/openexr/pull/2476) + Fix the DWAA size checks regression +* [2472](https://github.com/AcademySoftwareFoundation/openexr/pull/2472) + Unlock write context in exr_get_chunk_table_offset() return paths +* [2471](https://github.com/AcademySoftwareFoundation/openexr/pull/2471) + Add section on CVE Assignment to SECURITY.md +* [2470](https://github.com/AcademySoftwareFoundation/openexr/pull/2470) + Reject NULL bytes type_hint and data in exr_attr_bytes_create() +* [2468](https://github.com/AcademySoftwareFoundation/openexr/pull/2468) + Fix infinite loop in SampleCountChannel roundListSizeUp() +* [2466](https://github.com/AcademySoftwareFoundation/openexr/pull/2466) + Fix install manifest for linux build 13 +* [2464](https://github.com/AcademySoftwareFoundation/openexr/pull/2464) + Fix heap out-of-bounds write in SampleCountChannel row setter. +* [2463](https://github.com/AcademySoftwareFoundation/openexr/pull/2463) + Fix integer overflow and invalid delete in OpenEXRUtil Image::resize() +* [2451](https://github.com/AcademySoftwareFoundation/openexr/pull/2451) + Initialize B44 tables before B44A decode +* [2445](https://github.com/AcademySoftwareFoundation/openexr/pull/2445) + Fix: Allow NumPy scalar values in Box2i and V2f tuple bindings +* [2444](https://github.com/AcademySoftwareFoundation/openexr/pull/2444) + Fix vendored OpenJPH for static builds +* [2442](https://github.com/AcademySoftwareFoundation/openexr/pull/2442) + Bugfix: Fix interger overflows +* [2438](https://github.com/AcademySoftwareFoundation/openexr/pull/2438) + Break release.py into separate small scripts for each step +* [2436](https://github.com/AcademySoftwareFoundation/openexr/pull/2436) + Release notes and news for v3.4.12 +* [2434](https://github.com/AcademySoftwareFoundation/openexr/pull/2434) + Validate HTJ2K chunk header length before decode +* [2433](https://github.com/AcademySoftwareFoundation/openexr/pull/2433) + Tighten python publish workflow security/efficiency +* [2430](https://github.com/AcademySoftwareFoundation/openexr/pull/2430) + Pin idna>=3.15 in website/requirements.txt + +### Merged Workflow Pull Requests + +* [2479](https://github.com/AcademySoftwareFoundation/openexr/pull/2479) + Split macOS wheel arches across CI runners +* [2474](https://github.com/AcademySoftwareFoundation/openexr/pull/2474) + Bump msys2/setup-msys2 from 2.31.1 to 2.32.0 +* [2467](https://github.com/AcademySoftwareFoundation/openexr/pull/2467) + Bump sigstore/gh-action-sigstore-python from 3.3.0 to 3.4.0 +* [2462](https://github.com/AcademySoftwareFoundation/openexr/pull/2462) + Update idna requirement from >=3.17 to >=3.18 in /website +* [2450](https://github.com/AcademySoftwareFoundation/openexr/pull/2450) + Update idna requirement from >=3.15 to >=3.17 in /website +* [2449](https://github.com/AcademySoftwareFoundation/openexr/pull/2449) + Bump vmactions/freebsd-vm from 1.4.5 to 1.4.6 +* [2437](https://github.com/AcademySoftwareFoundation/openexr/pull/2437) + Bump github/codeql-action from 4.35.4 to 4.36.0 +* [2433](git@github.com:AcademySoftwareFoundation/openexr/pull/2433) + Tighten python publish workflow security/efficiency +* [2430](git@github.com:AcademySoftwareFoundation/openexr/pull/2430) + Pin idna>=3.15 in website/requirements.txt + + ## Version 3.4.12 (May 24, 2026) Patch release that addresses several bugs and security @@ -1035,6 +1125,34 @@ Fetch master branch of libdeflate on main * [1852](https://github.com/AcademySoftwareFoundation/openexr/pull/1852) Add an option to use TBB as the global provider +## Version 3.3.12 (June 21, 2026) + +This release addresses the following security vulnerabilities: + +* [CVE-2026-55373](https://www.cve.org/CVERecord?id=CVE-2026-55373) + OpenEXRUtil SampleCountChannel endEdit() can loop forever on UINT_MAX sample counts +* [CVE-2026-55059](https://www.cve.org/CVERecord?id=CVE-2026-55059) + OpenEXRUtil SampleCountChannel row setter heap out-of-bounds write +* [CVE-2026-54920](https://www.cve.org/CVERecord?id=CVE-2026-54920) + Integer Overflow and Use of Uninitialized Pointer leading to Invalid Delete in OpenEXRUtil Image Resize + +### Merged Pull Requests + + * [2476](git@github.com:AcademySoftwareFoundation/openexr/pull/2476) +Fix the DWAA size checks regression + * [2472](git@github.com:AcademySoftwareFoundation/openexr/pull/2472) +Unlock write context in exr_get_chunk_table_offset() return paths + * [2468](git@github.com:AcademySoftwareFoundation/openexr/pull/2468) +Fix infinite loop in SampleCountChannel roundListSizeUp() + * [2464](git@github.com:AcademySoftwareFoundation/openexr/pull/2464) +Fix heap out-of-bounds write in SampleCountChannel row setter. + * [2463](git@github.com:AcademySoftwareFoundation/openexr/pull/2463) +Fix integer overflow and invalid delete in OpenEXRUtil Image::resize() + * [2442](git@github.com:AcademySoftwareFoundation/openexr/pull/2442) +Bugfix: Fix interger overflows + * [2438](git@github.com:AcademySoftwareFoundation/openexr/pull/2438) +Break release.py into separate small scripts for each step + ## Version 3.3.11 (April 29, 2026) Patch release for 3.3 that addresses the following security @@ -1760,6 +1878,36 @@ Fix macOS arm64 build Propagate dwa core 3 1 * [1418](https://github.com/AcademySoftwareFoundation/openexr/pull/1418) +## Version 3.2.10 (June 21, 2026) + +Patch release for 3.2 addressing security issues. + +This release addresses the following security vulnerabilities: + +* [CVE-2026-55373](https://www.cve.org/CVERecord?id=CVE-2026-55373) + OpenEXRUtil SampleCountChannel endEdit() can loop forever on UINT_MAX sample counts +* [CVE-2026-55059](https://www.cve.org/CVERecord?id=CVE-2026-55059) + OpenEXRUtil SampleCountChannel row setter heap out-of-bounds write +* [CVE-2026-54920](https://www.cve.org/CVERecord?id=CVE-2026-54920) + Integer Overflow and Use of Uninitialized Pointer leading to Invalid Delete in OpenEXRUtil Image Resize + +### Merged Pull Requests + + * [2476](git@github.com:AcademySoftwareFoundation/openexr/pull/2476) +Fix the DWAA size checks regression + * [2472](git@github.com:AcademySoftwareFoundation/openexr/pull/2472) +Unlock write context in exr_get_chunk_table_offset() return paths + * [2468](git@github.com:AcademySoftwareFoundation/openexr/pull/2468) +Fix infinite loop in SampleCountChannel roundListSizeUp() + * [2464](git@github.com:AcademySoftwareFoundation/openexr/pull/2464) +Fix heap out-of-bounds write in SampleCountChannel row setter. + * [2463](git@github.com:AcademySoftwareFoundation/openexr/pull/2463) +Fix integer overflow and invalid delete in OpenEXRUtil Image::resize() + * [2442](git@github.com:AcademySoftwareFoundation/openexr/pull/2442) +Bugfix: Fix interger overflows + * [2438](git@github.com:AcademySoftwareFoundation/openexr/pull/2438) +Break release.py into separate small scripts for each step + ## Version 3.2.9 (April 29, 2026) Patch release for 3.2 that addresses the following security diff --git a/website/latest_news_title.rst b/website/latest_news_title.rst index 7ebd5076d..819cb831c 100644 --- a/website/latest_news_title.rst +++ b/website/latest_news_title.rst @@ -1,4 +1,4 @@ .. SPDX-License-Identifier: BSD-3-Clause Copyright (c) Contributors to the OpenEXR Project. -.. |latest-news-title| replace:: **May 24, 2026 - OpenEXR 3.4.12 Released** \ No newline at end of file +.. |latest-news-title| replace:: **June 19, 2026 - OpenEXR 3.4.13 Released** \ No newline at end of file diff --git a/website/news.rst b/website/news.rst index 378956fc6..f7f4a06a8 100644 --- a/website/news.rst +++ b/website/news.rst @@ -17,13 +17,58 @@ News |latest-news-title| -====================================== +======================================= .. _LatestNewsStart: Patch release that addresses several bugs and security vulnerabilities. +* 🐛 Fix a regression introduced in v3.4.11 in decoding of DWAA compression +* 🐛 Fix to handling deep images and very large images with the OpenEXRUtil library +* 🐛 Fix initiliazation issue in B44A decoding +* 🐛 Validate HTJ2K chunk header length before decode +* 🛠️ Fix when building statically and using the vendored OpenJPH library + +For the python module: + +* 🐍 ✨ Support NumPy scalar values Box2i and V2f tuple bindings + +This release addresses the following security vulnerabilities: + +* `CVE-2026-55373 `_ + OpenEXRUtil ``SampleCountChannel`` ``endEdit()`` can loop forever on ``UINT_MAX`` sample counts +* `CVE-2026-55371 `_ + OpenEXRCore ``exr_attr_set_bytes()`` accepts NULL ``type_hint`` with positive ``hint_length`` +* `CVE-2026-55059 `_ + OpenEXRUtil ``SampleCountChannel`` row setter heap out-of-bounds write +* `CVE-2026-54920 `_ + Integer Overflow and Use of Uninitialized Pointer leading to Invalid Delete in OpenEXRUtil Image Resize +* `CVE-2026-53532 `_ + Unhandled assert abort in HTJ2K decoder via crafted QCD marker (DoS) + +.. _LatestNewsEnd: + +June 21, 2026 - OpenEXR 3.3.12 and OpenEXR v3.2.10 Released +=========================================================== + +Patch releases for v3.3 and v3.2 that address the following security +vulnerabilities: + +* `CVE-2026-55373 `_ + OpenEXRUtil ``SampleCountChannel`` ``endEdit()`` can loop forever on ``UINT_MAX`` sample counts +* `CVE-2026-55059 `_ + OpenEXRUtil ``SampleCountChannel`` row setter heap out-of-bounds write +* `CVE-2026-54920 `_ + Integer Overflow and Use of Uninitialized Pointer leading to Invalid Delete in OpenEXRUtil Image Resize + + +May 24, 2026 - OpenEXR 3.4.12 Released +====================================== + +Patch release that addresses several bugs and security +vulnerabilities. + * 🐛 Fix several minor memory leaks recovering from reading invalid files. * 🐛 The compressor API incorrectly identfied ``HTJ2K`` and ``HTJ2K256`` as @@ -58,7 +103,6 @@ This release addresses the following security vulnerabilities: * `OSS-fuzz 507413960 `_ Heap-buffer-overflow in ``generic_unpack`` -.. _LatestNewsEnd: April 29, 2026 - OpenEXR 3.4.11 Released ======================================== From f498987dc403b524d6d1e36c7795ab2c52dffaed Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Sun, 28 Jun 2026 20:14:29 -0700 Subject: [PATCH 29/63] Update SECURITY.md with CVE fixes from v3.4.12 and 3.4.13 (#2501) Signed-off-by: Cary Phillips --- SECURITY.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/SECURITY.md b/SECURITY.md index f613e5de9..06e7a2bfd 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -39,6 +39,13 @@ it through normal use of the library. | CVE | Affected Versions | Patched Versions | | --- | ----------------- | ---------------- | +| [CVE-2026-55373](https://www.cve.org/CVERecord?id=CVE-2026-55373) | 2.x, 3.0.x, 3.1.x, 3.2.0–3.2.9, 3.3.0–3.3.11, 3.4.0–3.4.12 | 3.2.10, 3.3.12, 3.4.13 | +| [CVE-2026-55371](https://www.cve.org/CVERecord?id=CVE-2026-55371) | 3.4.0–3.4.12 | 3.4.13 | +| [CVE-2026-55059](https://www.cve.org/CVERecord?id=CVE-2026-55059) | 2.x, 3.0.x, 3.1.x, 3.2.0–3.2.9, 3.3.0–3.3.11, 3.4.0–3.4.12 | 3.2.10, 3.3.12, 3.4.13 | +| [CVE-2026-54920](https://www.cve.org/CVERecord?id=CVE-2026-54920) | 2.x, 3.0.x, 3.1.x, 3.2.0–3.2.9, 3.3.0–3.3.11, 3.4.0–3.4.12 | 3.2.10, 3.3.12, 3.4.13 | +| [CVE-2026-53532](https://www.cve.org/CVERecord?id=CVE-2026-53532) | 3.4.0–3.4.12 | 3.4.13 | +| [CVE-2026-45696](https://www.cve.org/CVERecord?id=CVE-2026-45696) | 3.4.0–3.4.11 | 3.4.12 | +| [CVE-2026-44663](https://www.cve.org/CVERecord?id=CVE-2026-44663) | 3.4.0–3.4.11 | 3.4.12 | | [CVE-2026-42217](https://www.cve.org/CVERecord?id=CVE-2026-42217) | 3.2.0–3.2.8, 3.3.0–3.3.10, 3.4.0–3.4.10 | 3.2.9, 3.3.11, 3.4.11 | | [CVE-2026-42216](https://www.cve.org/CVERecord?id=CVE-2026-42216) | 3.2.0–3.2.8, 3.3.0–3.3.10, 3.4.0–3.4.10 | 3.2.9, 3.3.11, 3.4.11 | | [CVE-2026-41142](https://www.cve.org/CVERecord?id=CVE-2026-41142) | 3.2.0–3.2.8, 3.3.0–3.3.10, 3.4.0–3.4.10 | 3.2.9, 3.3.11, 3.4.11 | From 020fced5580088c013902939cf67894d637982b6 Mon Sep 17 00:00:00 2001 From: peterhillman Date: Mon, 29 Jun 2026 15:15:59 +1200 Subject: [PATCH 30/63] prevent warning of potential double-free in ImfTiledMisc (#2503) Signed-off-by: Peter Hillman Co-authored-by: Cary Phillips --- src/lib/OpenEXR/ImfTiledMisc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/OpenEXR/ImfTiledMisc.cpp b/src/lib/OpenEXR/ImfTiledMisc.cpp index 9b5f816be..38ba8929c 100644 --- a/src/lib/OpenEXR/ImfTiledMisc.cpp +++ b/src/lib/OpenEXR/ImfTiledMisc.cpp @@ -378,7 +378,9 @@ getTiledChunkOffsetTableSize (const Header& header) "Bad level mode getting chunk offset table size"); } delete[] numXTiles; + numXTiles = nullptr; delete[] numYTiles; + numYTiles = nullptr; return static_cast (lineOffsetSize); } From 6494bbc701e1a7af9ec7dd49cdd8624326ffd189 Mon Sep 17 00:00:00 2001 From: peterhillman Date: Mon, 29 Jun 2026 15:17:03 +1200 Subject: [PATCH 31/63] fix --help message in exrmetrics (#2504) Signed-off-by: Peter Hillman Co-authored-by: Cary Phillips --- src/bin/exrmetrics/main.cpp | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/bin/exrmetrics/main.cpp b/src/bin/exrmetrics/main.cpp index 117813d36..18adb1871 100644 --- a/src/bin/exrmetrics/main.cpp +++ b/src/bin/exrmetrics/main.cpp @@ -57,6 +57,7 @@ usageMessage (ostream& stream, const char* program_name, bool verbose = false) "\n" " -o file file to write to. If no file specified, uses a memory buffer\n" " note: file may be overwritten multiple times during tests\n" + "\n" " -p n part number to copy, or \"all\" for all parts\n" " default is \"all\" \n" "\n" @@ -72,31 +73,40 @@ usageMessage (ostream& stream, const char* program_name, bool verbose = false) << ",orig,all\n" " default orig: retains original method)\n" + "\n" " --convert shorthand options for writing a new file with no metrics:\n" - " -p all --type orig --time none --type orig --no-size --passes 1\n" - " change pixel type or compression by specifying --type or -z after --convert\n" + " -p all --time none --pixelmode orig --no-size --passes 1\n" + " change pixel data type/compression by specifying --pixelmode/-z after --convert\n" + "\n" " --bench shorthand options for robust performance benchmarking:\n" " -p all --compression all --time write,reread --passes 10 --type half,float --no-size --csv\n" "\n" " -16 rgba|all [DEPRECATED] force 16 bit half float: either just RGBA, or all channels\n" - " Use --type half or --type mixed instead\n" - " --pixelmode list list of pixel types to use (float,half,mixed,orig)\n" + " Use --pixelmode half or --pixelmode mixed instead\n" + "\n" + " --pixelmode list list of pixel data types to use (float,half,mixed,orig)\n" " mixed uses half for RGBA, float for others. Default is 'orig'\n" - " --time list comma separated list of operations to report timing for.\n" + "\n" + " --time list comma separated list of operations to report timing for.\n" " operations can be any of read,write,reread (use --time none for no timing)\n" - " --no-size don't output size data\n" - " --part-disk-size Output the on-disk size of the data portion of each part in a multipart EXR file\n" + "\n" + " --no-size don't output size data\n" + "\n" + " --part-disk-size Output the on-disk size of the data portion of each part in a multipart EXR file\n" " (including chunk headers). File output (-o) is not supported when using this option\n" - " --json print output as JSON dictionary (Default mode)\n" - " --csv print output in csv mode. If passes>1, show median timing\n" + "\n" + " --json print output as JSON dictionary (Default mode)\n" + "\n" + " --csv print output in csv mode. If passes>1, show median timing\n" " default is JSON mode\n" - " --passes num write and re-read file num times (default 1)\n" + "\n" + " --passes num write and re-read file num times (default 1)\n" "\n" " -h, --help print this message\n" + "\n" " -v output progress messages\n" "\n" - " --version print version information\n" - "\n"; + " --version print version information\n"; } } From c5ce57d2f7ced287b0a10e7856e028b7c116fbd1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jun 2026 20:18:03 -0700 Subject: [PATCH 32/63] Bump actions/setup-python from 6.2.0 to 6.3.0 (#2505) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.2.0 to 6.3.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/a309ff8b426b58ec0e2a45f0f869d46889d02405...ece7cb06caefa5fff74198d8649806c4678c61a1) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 6.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/python-wheels-publish-test.yml | 2 +- .github/workflows/python-wheels-publish.yml | 2 +- .github/workflows/python-wheels.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/python-wheels-publish-test.yml b/.github/workflows/python-wheels-publish-test.yml index eba5cf512..57b9c089d 100644 --- a/.github/workflows/python-wheels-publish-test.yml +++ b/.github/workflows/python-wheels-publish-test.yml @@ -81,7 +81,7 @@ jobs: - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: '3.x' diff --git a/.github/workflows/python-wheels-publish.yml b/.github/workflows/python-wheels-publish.yml index cd940d098..92bc65af1 100644 --- a/.github/workflows/python-wheels-publish.yml +++ b/.github/workflows/python-wheels-publish.yml @@ -77,7 +77,7 @@ jobs: - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: '3.x' diff --git a/.github/workflows/python-wheels.yml b/.github/workflows/python-wheels.yml index c513b5056..10d841e40 100644 --- a/.github/workflows/python-wheels.yml +++ b/.github/workflows/python-wheels.yml @@ -65,7 +65,7 @@ jobs: - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: '3.x' From 19241b90a8b461d7058275546e63f9fc7b3f1814 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jun 2026 20:18:30 -0700 Subject: [PATCH 33/63] Bump actions/cache from 5.0.5 to 6.0.0 (#2506) Bumps [actions/cache](https://github.com/actions/cache) from 5.0.5 to 6.0.0. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/27d5ce7f107fe9357f9df03efb73ab90386fccae...2c8a9bd7457de244a408f35966fab2fb45fda9c8) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/bazel_build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bazel_build.yml b/.github/workflows/bazel_build.yml index caa5b21ab..51a88437d 100644 --- a/.github/workflows/bazel_build.yml +++ b/.github/workflows/bazel_build.yml @@ -42,7 +42,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Mount Bazel cache - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 with: path: "/home/runner/.cache/bazel" key: bazel-ubuntu-24 @@ -60,7 +60,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Mount Bazel cache - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 with: path: "/home/runner/.cache/bazel" key: bazel-windows-2025 @@ -78,7 +78,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Mount Bazel cache - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 with: path: "/home/runner/.cache/bazel" key: bazel-macos-15 From 96fc617cf222b705df92f242ff56126735ebb1a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jun 2026 20:19:26 -0700 Subject: [PATCH 34/63] Bump rules_cc from 0.2.19 to 0.2.20 (#2511) Bumps [rules_cc](https://github.com/bazelbuild/rules_cc) from 0.2.19 to 0.2.20. - [Release notes](https://github.com/bazelbuild/rules_cc/releases) - [Commits](https://github.com/bazelbuild/rules_cc/compare/0.2.19...0.2.20) --- updated-dependencies: - dependency-name: rules_cc dependency-version: 0.2.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index 32199806c..5b6de5c81 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,4 +11,4 @@ bazel_dep(name = "imath", version = "3.2.2.bcr.1") bazel_dep(name = "libdeflate", version = "1.25") bazel_dep(name = "openjph", version = "0.27.3.bcr.1") bazel_dep(name = "platforms", version = "1.1.0") -bazel_dep(name = "rules_cc", version = "0.2.19") +bazel_dep(name = "rules_cc", version = "0.2.20") From 3a4214aa73041c194e450cdd6a52c0bf9f17a237 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Fri, 3 Jul 2026 19:26:44 -0700 Subject: [PATCH 35/63] Fix ILP32 B44/B44A scratch buffer overflow in decode (#2491) compute_scratch_buffer_size() returns uint64_t, but internal_decode_alloc_buffer() takes size_t. On ILP32 builds the implicit conversion silently truncates scratch sizes above 4 GiB, causing uncompress_b44_impl() to write far past the undersized allocation using the attacker-controlled channel width. Add an explicit truncation check before both the B44 and B44A scratch buffer allocations: if the required size exceeds SIZE_MAX, return EXR_ERR_OUT_OF_MEMORY rather than allocating a truncated buffer. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-92pq-9qv4-g68q Signed-off-by: Cary Phillips Co-authored-by: Claude Sonnet 4.6 --- src/lib/OpenEXRCore/internal_b44.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib/OpenEXRCore/internal_b44.c b/src/lib/OpenEXRCore/internal_b44.c index 99d35a7fd..f30762ccd 100644 --- a/src/lib/OpenEXRCore/internal_b44.c +++ b/src/lib/OpenEXRCore/internal_b44.c @@ -694,12 +694,14 @@ internal_exr_undo_b44 ( uint64_t uncompressed_size) { exr_result_t rv; + uint64_t scratch_sz = compute_scratch_buffer_size (decode, uncompressed_size); + if (scratch_sz != (size_t) scratch_sz) return EXR_ERR_OUT_OF_MEMORY; rv = internal_decode_alloc_buffer ( decode, EXR_TRANSCODE_BUFFER_SCRATCH1, &(decode->scratch_buffer_1), &(decode->scratch_alloc_size_1), - compute_scratch_buffer_size (decode, uncompressed_size)); + (size_t) scratch_sz); if (rv != EXR_ERR_SUCCESS) return rv; exrcore_ensure_b44_tables (); @@ -721,12 +723,14 @@ internal_exr_undo_b44a ( uint64_t uncompressed_size) { exr_result_t rv; + uint64_t scratch_sz = compute_scratch_buffer_size (decode, uncompressed_size); + if (scratch_sz != (size_t) scratch_sz) return EXR_ERR_OUT_OF_MEMORY; rv = internal_decode_alloc_buffer ( decode, EXR_TRANSCODE_BUFFER_SCRATCH1, &(decode->scratch_buffer_1), &(decode->scratch_alloc_size_1), - compute_scratch_buffer_size (decode, uncompressed_size)); + (size_t) scratch_sz); if (rv != EXR_ERR_SUCCESS) return rv; exrcore_ensure_b44_tables (); From 4aa1b6092535fd913126b6f06747cbdd2d038e40 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Fri, 3 Jul 2026 19:29:26 -0700 Subject: [PATCH 36/63] Reject mixed pixel types when coalescing RGB channels in PyOpenEXR. (#2502) Deep and flat reads with separate_channels=False assumed all coalesced R/G/B channels share one PixelType, which could undersize NumPy buffers and cause heap corruption on decode. Validate types before reading and propagate invalid_argument to Python; add regression tests. For example, if the file has left.R, left.G, left.B, it's an error to request an RGB pixel array if "left.R" is FLOAT and "left.G" is HALF. However, it's OK for all "left" channels to be FLOAT and all "right" channels to be HALF. Note also that attempting to combine mixed-type channels causes a failure to read the entire file, whereas other read errors simply skip the offending part. This is reasonable behavior since the condition is not a defect in the data itself, but simply an inability to return the data in the format the user requested. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-994f-rr2m-9r7x Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/wrappers/python/PyOpenEXR.cpp | 86 +++++++++++++++++++++++++- src/wrappers/python/PyOpenEXR.h | 8 ++- src/wrappers/python/tests/test_deep.py | 67 ++++++++++++++++++++ 3 files changed, 158 insertions(+), 3 deletions(-) diff --git a/src/wrappers/python/PyOpenEXR.cpp b/src/wrappers/python/PyOpenEXR.cpp index 934ff3d91..b9b5beb05 100644 --- a/src/wrappers/python/PyOpenEXR.cpp +++ b/src/wrappers/python/PyOpenEXR.cpp @@ -431,6 +431,9 @@ PyFile::readPartsFromOpenInput(bool separate_channels) std::vector shape ({height, width}); + if (!separate_channels) + P.validateCoalescedChannelTypes (header.channels (), rgbaChannels); + // // Read the channel data, different for image vs. deep // @@ -448,6 +451,10 @@ PyFile::readPartsFromOpenInput(bool separate_channels) } parts.append(py::cast(PyPart(P))); } + catch (const std::invalid_argument&) + { + throw; + } catch (const std::exception& e) { // Log the error and skip appending this part @@ -467,6 +474,9 @@ PyPart::readPixels(MultiPartInputFile& infile, const ChannelList& channel_list, const std::vector& shape, const std::set& rgbaChannels, const Box2i& dw, bool separate_channels) { + if (!separate_channels) + validateCoalescedChannelTypes (channel_list, rgbaChannels); + FrameBuffer frameBuffer; for (auto c = channel_list.begin(); c != channel_list.end(); c++) @@ -719,6 +729,9 @@ PyPart::readDeepPixels(MultiPartInputFile& infile, const std::string& type, cons const std::vector& shape, const std::set& rgbaChannels, const Box2i& dw, bool separate_channels) { + if (!separate_channels) + validateCoalescedChannelTypes (channel_list, rgbaChannels); + size_t width = dw.max.x - dw.min.x + 1; size_t height = dw.max.y - dw.min.y + 1; auto dw_offset = dw.min.y * width + dw.min.x; @@ -1177,9 +1190,80 @@ PyPart::writeDeepPixels(MultiPartOutputFile& outfile, const Box2i& dw) const // channel_name is returned as the single character name of the channel // +namespace +{ + +const char* +pixelTypeName (PixelType type) +{ + switch (type) + { + case UINT: return "UINT"; + case HALF: return "HALF"; + case FLOAT: return "FLOAT"; + default: return "unknown"; + } +} + +} // namespace + +// +// Only combine RGB(A) channels into a single numpy array when they all have +// the same pixel type. For example, if red is HALF and green is FLOAT, an +// attempt to return an RGB pixel array will throw an exception. +// +// Note that attempting to combine mixed-type channels causes a failure of +// the entire file read, whereas other read errors simply skip the offending +// part. This is reasonable behavior since the condition is not a defect in +// the data itself, but simply an inability to return the data in the format +// the user requested. + +void +PyPart::validateCoalescedChannelTypes ( + const ChannelList& channel_list, + const std::set& rgbaChannels) const +{ + if (rgbaChannels.empty ()) + return; + + std::map groupType; + + for (auto c = channel_list.begin (); c != channel_list.end (); ++c) + { + if (rgbaChannels.find (c.name ()) == rgbaChannels.end ()) + continue; + + // py_channel_name is the name of the combined channel, i.e. if the + // file has left.R, left.G, left.B, then py_channel_name is "left". + // It's allowable to have "left" be FLOAT and "right" be HALF, but + // all RGB channels within "left" and "right" must have the same + // type. + + std::string py_channel_name; + char channel_name; + if (channelNameToRGBA (channel_list, c.name (), py_channel_name, channel_name) <= 0) + continue; + + const PixelType channelType = c.channel ().type; + auto it = groupType.find (py_channel_name); + if (it == groupType.end ()) + groupType[py_channel_name] = channelType; + else if (it->second != channelType) + { + std::stringstream err; + err << "cannot coalesce channels into \"" << py_channel_name + << "\": channel \"" << c.name () << "\" has pixel type " + << pixelTypeName (channelType) << " but other channels in the group " + << "have pixel type " << pixelTypeName (it->second) + << "; use separate_channels=True"; + throw std::invalid_argument (err.str ()); + } + } +} + int PyPart::channelNameToRGBA(const ChannelList& channel_list, const std::string& name, - std::string& py_channel_name, char& channel_name) + std::string& py_channel_name, char& channel_name) const { py_channel_name = name; channel_name = py_channel_name.back(); diff --git a/src/wrappers/python/PyOpenEXR.h b/src/wrappers/python/PyOpenEXR.h index eb374246b..3588669da 100644 --- a/src/wrappers/python/PyOpenEXR.h +++ b/src/wrappers/python/PyOpenEXR.h @@ -140,8 +140,12 @@ class PyPart const std::vector& shape, const std::set& rgbaChannels, const Box2i& dw, bool separate_channels); int channelNameToRGBA(const ChannelList& channel_list, const std::string& name, - std::string& py_channel_name, char& channel_name); - + std::string& py_channel_name, char& channel_name) const; + + void validateCoalescedChannelTypes( + const ChannelList& channel_list, + const std::set& rgbaChannels) const; + }; // diff --git a/src/wrappers/python/tests/test_deep.py b/src/wrappers/python/tests/test_deep.py index dc31ed3a7..14a9464ff 100644 --- a/src/wrappers/python/tests/test_deep.py +++ b/src/wrappers/python/tests/test_deep.py @@ -224,6 +224,73 @@ def test_tiled_deep(self): os.remove(filename) + def test_mixed_type_rgb_coalesce_deep_rejected(self): + dataWindow = ((0, 0), (0, 0)) + height = width = 1 + + B = np.empty((height, width), dtype=object) + G = np.empty((height, width), dtype=object) + R = np.empty((height, width), dtype=object) + B[0, 0] = np.array([1.0, 2.0], dtype='float16') + G[0, 0] = np.array([1.0, 2.0], dtype='float32') + R[0, 0] = np.array([1.0, 2.0], dtype='float32') + + channels = {"B": B, "G": G, "R": R} + header = { + "compression": OpenEXR.ZIPS_COMPRESSION, + "type": OpenEXR.deepscanline, + "dataWindow": dataWindow, + } + + fd, path = tempfile.mkstemp(suffix=".exr") + os.close(fd) + try: + with OpenEXR.File(header, channels) as outfile: + outfile.write(path) + + with self.assertRaises(Exception) as ctx: + OpenEXR.File(path) + self.assertIn("separate_channels", str(ctx.exception)) + + with OpenEXR.File(path, separate_channels=True) as infile: + self.assertIn("B", infile.channels()) + self.assertIn("G", infile.channels()) + self.assertIn("R", infile.channels()) + finally: + if os.path.exists(path): + os.remove(path) + + def test_mixed_type_rgb_coalesce_flat_rejected(self): + dataWindow = ((0, 0), (0, 0)) + + channels = { + "B": np.array([[1.0]], dtype='float16'), + "G": np.array([[2.0]], dtype='float32'), + "R": np.array([[3.0]], dtype='float32'), + } + header = { + "type": OpenEXR.scanlineimage, + "dataWindow": dataWindow, + } + + fd, path = tempfile.mkstemp(suffix=".exr") + os.close(fd) + try: + with OpenEXR.File(header, channels) as outfile: + outfile.write(path) + + with self.assertRaises(Exception) as ctx: + OpenEXR.File(path) + self.assertIn("separate_channels", str(ctx.exception)) + + with OpenEXR.File(path, separate_channels=True) as infile: + self.assertIn("B", infile.channels()) + self.assertIn("G", infile.channels()) + self.assertIn("R", infile.channels()) + finally: + if os.path.exists(path): + os.remove(path) + if __name__ == '__main__': unittest.main() print("OK") From e198e44cea60eecd8a69deca89ed21da2f5785c2 Mon Sep 17 00:00:00 2001 From: AutoJanitor Date: Fri, 3 Jul 2026 22:08:21 -0500 Subject: [PATCH 37/63] Core: byte-swap the float vector data, not the attribute struct (#2510) extract_attr_float_vector reads the float array into attrdata->arr, then called priv_to_native32(attrdata, n). On big-endian hosts that swaps the first n 32-bit words of the exr_attr_float_vector_t struct itself (the arr pointer and length) instead of the n floats in attrdata->arr. The corrupted pointer and length then crash when the value is read back, for example a std::bad_alloc or segfault while constructing the FloatVector in the C++ Context::header path. Swap attrdata->arr instead. priv_to_native32 is a no-op on little-endian, so x86_64 and ppc64le are unaffected. Verified on POWER8: OpenEXR.testAttributes segfaults on big-endian ppc64 before this change and passes after. Signed-off-by: Scott Boudreaux <121303252+Scottcjn@users.noreply.github.com> Co-authored-by: Cary Phillips --- src/lib/OpenEXRCore/parse_header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/OpenEXRCore/parse_header.c b/src/lib/OpenEXRCore/parse_header.c index 575707d0e..af0fd2569 100644 --- a/src/lib/OpenEXRCore/parse_header.c +++ b/src/lib/OpenEXRCore/parse_header.c @@ -557,7 +557,7 @@ extract_attr_float_vector ( tname); } - priv_to_native32 (attrdata, n); + priv_to_native32 (attrdata->arr, n); } return rv; From 0c28bc31fe15a45f20e37c3157a6ba1b1694045d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:11:43 -0700 Subject: [PATCH 38/63] Bump vmactions/freebsd-vm from 1.4.8 to 1.5.0 (#2513) Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm) from 1.4.8 to 1.5.0. - [Release notes](https://github.com/vmactions/freebsd-vm/releases) - [Commits](https://github.com/vmactions/freebsd-vm/compare/b84ab5559b5a1bb4b8ee2737d2506a16e1737636...5a72679103d223925653750faa878a143340fbd0) --- updated-dependencies: - dependency-name: vmactions/freebsd-vm dependency-version: 1.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/ci_freebsd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_freebsd.yml b/.github/workflows/ci_freebsd.yml index f44bb814b..f51f48e6a 100644 --- a/.github/workflows/ci_freebsd.yml +++ b/.github/workflows/ci_freebsd.yml @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Build and test on FreeBSD - uses: vmactions/freebsd-vm@b84ab5559b5a1bb4b8ee2737d2506a16e1737636 # v1.4.8 + uses: vmactions/freebsd-vm@5a72679103d223925653750faa878a143340fbd0 # v1.5.0 with: release: '15.0' envs: GITHUB_REPOSITORY GITHUB_REF GITHUB_SHA From 47213f2acd137f43edaa9649f249ba9c4ebc5acb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:12:10 -0700 Subject: [PATCH 39/63] Bump actions/cache from 6.0.0 to 6.1.0 (#2514) Bumps [actions/cache](https://github.com/actions/cache) from 6.0.0 to 6.1.0. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/2c8a9bd7457de244a408f35966fab2fb45fda9c8...55cc8345863c7cc4c66a329aec7e433d2d1c52a9) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/bazel_build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bazel_build.yml b/.github/workflows/bazel_build.yml index 51a88437d..dc8b85134 100644 --- a/.github/workflows/bazel_build.yml +++ b/.github/workflows/bazel_build.yml @@ -42,7 +42,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Mount Bazel cache - uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: "/home/runner/.cache/bazel" key: bazel-ubuntu-24 @@ -60,7 +60,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Mount Bazel cache - uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: "/home/runner/.cache/bazel" key: bazel-windows-2025 @@ -78,7 +78,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Mount Bazel cache - uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: "/home/runner/.cache/bazel" key: bazel-macos-15 From a1cf86438fe02b900bb218089e5251b9ba59226e Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Fri, 3 Jul 2026 20:28:57 -0700 Subject: [PATCH 40/63] Update security policy regarding CVE requests (#2512) * Update security policy regarding CVE requests Clarify the conditions under which we will/won't request CVEs. Signed-off-by: Cary Phillips * update policy on tool bugs Signed-off-by: Cary Phillips * remove confusing statement Signed-off-by: Cary Phillips --------- Signed-off-by: Cary Phillips --- SECURITY.md | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 06e7a2bfd..c1503e205 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -18,21 +18,33 @@ rapidly and post patches within 14 days if possible. ## CVE Assignment -We request a CVE when an untrusted party can plausibly trigger the flaw -through normal product inputs (for example, a crafted EXR or other data -the application is meant to process); otherwise we treat it as a regular -bugfix, document it in a GitHub security advisory or release notes when -helpful, and do not request a CVE for API-only or caller-controlled -failures with no realistic adversarial path. +Our criteria for requesting a CVE are: + +- Memory safety violations (out-of-bounds write, use-after-free, heap + corruption) reachable on mainstream 64-bit architectures through the + public library API, confirmed in an unsanitized build on a mainstream + platform, and affecting library code so that every downstream consumer + inherits the risk. + +We do not request a CVE for: + +- 32-bit-only bugs — bugs on 32-bit systems are real and will be fixed, + but since the vast majority of downstream packages (Linux distros, + conda-forge, vcpkg) build for 64-bit exclusively, a CVE creates + unnecessary work for maintainers who are not actually affected. + +- Developer-tool-only crashes (exrmetrics, exrcheck) — the library + itself and standard utility programs are safe; only users who run + one of the developer tools on untrusted input are exposed. Flaws whose root cause lies in a bundled dependency (such as OpenJPH) are fixed upstream; the upstream project owns the CVE when one is -warranted. Note that this applies even when a flaw is detected in -dependency code vendored into OpenEXR's `external/` source directory. -OpenEXR addresses them by updating the dependency and noting the -upstream advisory in release notes. We request a CVE for OpenEXR -itself only when the flaw is in our code and untrusted input can reach -it through normal use of the library. +warranted. This applies even when a flaw is detected in dependency code +vendored into OpenEXR's `external/` source directory. OpenEXR addresses +such flaws by updating the dependency and noting the upstream advisory +in the release notes. We request a CVE for OpenEXR itself only when the +flaw is in our code and untrusted input can reach it through normal use +of the library. ## Known Vulnerabilities From c949d3aded2bce3fa26fdd8311f48fb58243183a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:36:54 -0700 Subject: [PATCH 41/63] Bump github/codeql-action/init from 4.36.2 to 4.36.3 (#2521) Bumps [github/codeql-action/init](https://github.com/github/codeql-action) from 4.36.2 to 4.36.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...54f647b7e1bb85c95cddabcd46b0c578ec92bc1a) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.36.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 49eea6588..1dcf3628f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -68,7 +68,7 @@ jobs: # cary: Pin the version to the SHA for 2.18.0, since there appears to # be a problem with 2.18.1 leading to a "No space left on # device" failure - uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 + uses: github/codeql-action/init@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 with: # cary: the "linked" setting is necessary to force the run to pick up # the version specified in the action. From 4838d0e0dca6bd7b61f533e36d76eeabce95b8bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:37:22 -0700 Subject: [PATCH 42/63] Bump github/codeql-action/upload-sarif from 4.36.2 to 4.36.3 (#2520) Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.36.2 to 4.36.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...54f647b7e1bb85c95cddabcd46b0c578ec92bc1a) --- updated-dependencies: - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.36.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index fd72fa70d..18110bbd3 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -54,6 +54,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 + uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 with: sarif_file: results.sarif From 6f099ab35dacfbbf9d415a40ab8bff652e6bdbac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:37:53 -0700 Subject: [PATCH 43/63] Bump github/codeql-action/analyze from 4.36.2 to 4.36.3 (#2519) Bumps [github/codeql-action/analyze](https://github.com/github/codeql-action) from 4.36.2 to 4.36.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...54f647b7e1bb85c95cddabcd46b0c578ec92bc1a) --- updated-dependencies: - dependency-name: github/codeql-action/analyze dependency-version: 4.36.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1dcf3628f..63f7ec362 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -99,7 +99,7 @@ jobs: - name: Perform CodeQL Analysis # Pin the version to the SHA for 2.18.0 - uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 + uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 with: category: "/language:${{matrix.language}}" # For pull_request, upload against refs/pull//head + head SHA so the Code From 36ff0968de08d7ae80792f9f53402f93433207bb Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Sat, 4 Jul 2026 16:44:30 -0700 Subject: [PATCH 44/63] Fix name comparison in deep prefixed RGB channel coalescing (#2522) setDeepSliceData() used strcmp(c.name(), "G"/"B"/"A") to select the RGB channel offset, which only matched unprefixed channel names. For layer-prefixed channels like left.G and left.B the comparison failed, leaving channels 1 and 2 pointing at their initial (stale heap) data while channel 0 received all decoded samples. Fix: check only the final character of the channel name, consistent with how channelNameToRGBA() already identifies the channel suffix. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-pf59-r2mc-x746 Signed-off-by: Cary Phillips Co-authored-by: Claude Sonnet 4.6 --- src/wrappers/python/PyOpenEXR.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/wrappers/python/PyOpenEXR.cpp b/src/wrappers/python/PyOpenEXR.cpp index b9b5beb05..ba0d0f4b3 100644 --- a/src/wrappers/python/PyOpenEXR.cpp +++ b/src/wrappers/python/PyOpenEXR.cpp @@ -681,11 +681,12 @@ PyPart::setDeepSliceData(const ChannelList& channel_list, size_t height, size_t 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; } From d2ccc0b5cec8fc3b2fe1e2539f72220f09a59e6b Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Sun, 5 Jul 2026 18:53:12 -0700 Subject: [PATCH 45/63] Upgrade all manylinux cibuildwheel images to manylinux_2_28 (#2527) NumPy 2.5+ no longer ships manylinux_2_17 wheels and requires GCC >= 10.3 when building from source. The manylinux2014 containers only provides GCC 10.2.1, so cibuildwheel's test phase fails when pip cannot install numpy. Use manylinux_2_28 for aarch64, x86_64, and i686 builds (GCC 11, glibc 2.28), which has compatible pre-built numpy wheels and satisfies the compiler requirement. Signed-off-by: Cary Phillips Co-authored-by: Cursor --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d966f6f9c..18267dc07 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,9 +82,9 @@ test-extras = ["test"] test-skip = ["*universal2:arm64"] build-verbosity = 1 -manylinux-x86_64-image = "manylinux2014" -manylinux-i686-image = "manylinux2014" -manylinux-aarch64-image = "manylinux2014" +manylinux-x86_64-image = "manylinux_2_28" +manylinux-i686-image = "manylinux_2_28" +manylinux-aarch64-image = "manylinux_2_28" # Needed for full C++17 support [tool.cibuildwheel.macos.environment] From c7ba2278853ab6f6ba7a415187bf6e88afbc318f Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 6 Jul 2026 13:16:39 -0700 Subject: [PATCH 46/63] Fix exrmetrics heap OOB on subsampled scanlines (#2528) initScanLine() adjusted Slice base pointers using full pixel-space origin offsets, but OpenEXR addresses subsampled channels with origin.x / xSampling and origin.y / ySampling. Use Slice::Make() so the base pointer matches the library's coordinate math. Fixes https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-7h7v-98cr-8ppw Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/bin/exrmetrics/exrmetrics.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/bin/exrmetrics/exrmetrics.cpp b/src/bin/exrmetrics/exrmetrics.cpp index f1f1da178..46c19a7ba 100644 --- a/src/bin/exrmetrics/exrmetrics.cpp +++ b/src/bin/exrmetrics/exrmetrics.cpp @@ -80,8 +80,6 @@ initScanLine ( int numChans = channelCount (in.header ()); pixelData.resize (numChans); - uint64_t offsetToOrigin = width * static_cast (dw.min.y) + - static_cast (dw.min.x); int channelNumber = 0; size_t rawSize = 0; @@ -98,9 +96,10 @@ initScanLine ( buf.insert ( i.name (), - Slice ( + Slice::Make ( i.channel ().type, - pixelData[channelNumber].data () - offsetToOrigin * samplesize, + pixelData[channelNumber].data (), + dw, samplesize, samplesize * width, i.channel ().xSampling, From 13c2b4668644c545b8e9285cd6fbb5f2acba5307 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Fri, 10 Jul 2026 18:36:37 -0700 Subject: [PATCH 47/63] Group CodeQL GitHub Actions bumps in Dependabot. (#2523) Keep init, analyze, and upload-sarif on the same version so partial updates do not break the CodeQL workflow with a version mismatch. Signed-off-by: Cary Phillips Co-authored-by: Cursor --- .github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 442a41415..eccaa2529 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,6 +11,10 @@ updates: interval: "daily" exclude-paths: - ".github/workflows/ci_workflow_old.yml" + groups: + codeql: + patterns: + - "github/codeql-action/*" - package-ecosystem: "pip" directory: "/website" From 2d87209886fe4bd080c0b91111b429ac413fb2fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 21:37:58 -0700 Subject: [PATCH 48/63] Bump the codeql group with 3 updates (#2537) Bumps the codeql group with 3 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action). Updates `github/codeql-action/init` from 4.36.3 to 4.37.0 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/54f647b7e1bb85c95cddabcd46b0c578ec92bc1a...99df26d4f13ea111d4ec1a7dddef6063f76b97e9) Updates `github/codeql-action/analyze` from 4.36.3 to 4.37.0 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/54f647b7e1bb85c95cddabcd46b0c578ec92bc1a...99df26d4f13ea111d4ec1a7dddef6063f76b97e9) Updates `github/codeql-action/upload-sarif` from 4.36.3 to 4.37.0 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/54f647b7e1bb85c95cddabcd46b0c578ec92bc1a...99df26d4f13ea111d4ec1a7dddef6063f76b97e9) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: codeql - dependency-name: github/codeql-action/analyze dependency-version: 4.37.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: codeql - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: codeql ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 63f7ec362..cf6b105f0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -68,7 +68,7 @@ jobs: # cary: Pin the version to the SHA for 2.18.0, since there appears to # be a problem with 2.18.1 leading to a "No space left on # device" failure - uses: github/codeql-action/init@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 + uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 with: # cary: the "linked" setting is necessary to force the run to pick up # the version specified in the action. @@ -99,7 +99,7 @@ jobs: - name: Perform CodeQL Analysis # Pin the version to the SHA for 2.18.0 - uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 + uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 with: category: "/language:${{matrix.language}}" # For pull_request, upload against refs/pull//head + head SHA so the Code diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 18110bbd3..743b1502e 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -54,6 +54,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 + uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 with: sarif_file: results.sarif From a3ea48ac99cc2d9c24886e844fc9b99808f4b261 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 21:38:36 -0700 Subject: [PATCH 49/63] Bump rules_cc from 0.2.20 to 0.2.22 (#2538) Bumps [rules_cc](https://github.com/bazelbuild/rules_cc) from 0.2.20 to 0.2.22. - [Release notes](https://github.com/bazelbuild/rules_cc/releases) - [Commits](https://github.com/bazelbuild/rules_cc/compare/0.2.20...0.2.22) --- updated-dependencies: - dependency-name: rules_cc dependency-version: 0.2.22 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index 5b6de5c81..70c501885 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,4 +11,4 @@ bazel_dep(name = "imath", version = "3.2.2.bcr.1") bazel_dep(name = "libdeflate", version = "1.25") bazel_dep(name = "openjph", version = "0.27.3.bcr.1") bazel_dep(name = "platforms", version = "1.1.0") -bazel_dep(name = "rules_cc", version = "0.2.20") +bazel_dep(name = "rules_cc", version = "0.2.22") From 1dd2da169c9e5228f5e11f3f6c5ded16b53c19e7 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 13 Jul 2026 13:54:47 -0700 Subject: [PATCH 50/63] Fix exrmultiview heap OOB when union dataWindow misaligns with subsampling (#2530) * Fix exrmultiview heap OOB when union dataWindow misaligns with subsampling Validate the combined data window against each input channel's x/y subsampling before allocating pixel buffers or calling readPixels, matching ImfHeader checks. Reject misaligned unions with ArgExc instead of reading past undersized buffers. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-gjf7-wjjw-xq56 Co-authored-by: Cursor Signed-off-by: Cary Phillips * Reject all input with sampling != 1 Subsampling is rare, and exrmultiview not commonly used, so this solution seems cleaner: just don't handle subsampling at all. Signed-off-by: Cary Phillips --------- Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/bin/exrmultiview/makeMultiView.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bin/exrmultiview/makeMultiView.cpp b/src/bin/exrmultiview/makeMultiView.cpp index 1beebfef1..c78a06bbe 100644 --- a/src/bin/exrmultiview/makeMultiView.cpp +++ b/src/bin/exrmultiview/makeMultiView.cpp @@ -107,6 +107,14 @@ makeMultiView ( string inChanName = j.name (); string outChanName = insertViewName (inChanName, viewNames, i); + if (inChannel.xSampling != 1 || inChannel.ySampling != 1) + THROW (IEX_NAMESPACE::ArgExc, + "no support for subsampling:" + << " channel " << inChanName + << " of " << inFileNames[i] + << " has subsampling " << inChannel.xSampling + << ", " << inChannel.ySampling); + image.addChannel (outChanName, inChannel); image.channel (outChanName).black (); From d684e458285fd77cd756cb88fb5050df52cd7dbe Mon Sep 17 00:00:00 2001 From: Kimball Thurston <61098547+kthurston@users.noreply.github.com> Date: Mon, 13 Jul 2026 16:57:05 -0400 Subject: [PATCH 51/63] Add check to avoid overflow, add tests for reading / writing many channels (#2525) Signed-off-by: Kimball Thurston Co-authored-by: Cary Phillips --- src/lib/OpenEXRCore/channel_list.c | 12 ++++- src/test/OpenEXRCoreTest/general_attr.cpp | 16 +++++++ src/test/OpenEXRTest/testChannels.cpp | 57 +++++++++++++++++++++-- 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/lib/OpenEXRCore/channel_list.c b/src/lib/OpenEXRCore/channel_list.c index 61fc89acc..9165d6b02 100644 --- a/src/lib/OpenEXRCore/channel_list.c +++ b/src/lib/OpenEXRCore/channel_list.c @@ -173,7 +173,17 @@ exr_attr_chlist_add_with_length ( if (newcount > clist->num_alloced) { - int nsz = clist->num_alloced * 2; + int nsz; + + /* perhaps an arbitrary limit, but that is a LOT of channels */ + if (clist->num_alloced >= (INT32_MAX / 2)) + { + exr_attr_string_destroy (ctxt, &(nent.name)); + return ctxt->standard_error (ctxt, EXR_ERR_OUT_OF_MEMORY); + } + + nsz = clist->num_alloced * 2; + if (newcount > nsz) nsz = newcount + 1; nlist = (exr_attr_chlist_entry_t*) ctxt->alloc_fn ( sizeof (*nlist) * (size_t) nsz); diff --git a/src/test/OpenEXRCoreTest/general_attr.cpp b/src/test/OpenEXRCoreTest/general_attr.cpp index c11be86f0..429922031 100644 --- a/src/test/OpenEXRCoreTest/general_attr.cpp +++ b/src/test/OpenEXRCoreTest/general_attr.cpp @@ -803,6 +803,22 @@ testChlistHelper (exr_context_t f) // make sure we can re-delete something? EXRCORE_TEST_RVAL (exr_attr_chlist_destroy (f, &cl)); + + for ( int curc = 0; curc < 384; ++curc ) + { + char cname[32]; + /* use zero pad to avoid dealing with lexical ordering of channels */ + snprintf (cname, 32, "c%03d", curc); + EXRCORE_TEST_RVAL (exr_attr_chlist_add ( + f, &cl, cname, EXR_PIXEL_HALF, EXR_PERCEPTUALLY_LINEAR, 1, 2)); + EXRCORE_TEST (cl.num_channels == (curc + 1)); + EXRCORE_TEST (0 == strcmp (cl.entries[curc].name.str, cname)); + EXRCORE_TEST (cl.entries[curc].pixel_type == EXR_PIXEL_HALF); + EXRCORE_TEST (cl.entries[curc].p_linear == (uint8_t) EXR_PERCEPTUALLY_LINEAR); + EXRCORE_TEST (cl.entries[curc].x_sampling == 1); + EXRCORE_TEST (cl.entries[curc].y_sampling == 2); + } + EXRCORE_TEST_RVAL (exr_attr_chlist_destroy (f, &cl)); } void diff --git a/src/test/OpenEXRTest/testChannels.cpp b/src/test/OpenEXRTest/testChannels.cpp index 17c8fa1b4..2217a83f6 100644 --- a/src/test/OpenEXRTest/testChannels.cpp +++ b/src/test/OpenEXRTest/testChannels.cpp @@ -45,7 +45,8 @@ writeRead ( const Array2D& h2out, const char fileName[], int width, - int height) + int height, + bool manyC) { // // Write an image file with three channels, H1, H2 and H3. @@ -78,6 +79,17 @@ writeRead ( 1, // xSampling 1) // ySampling ); + if (manyC) + { + for ( int curc = 0; curc < 132; ++curc ) + { + char cname[32]; + snprintf (cname, 32, "c%03d", curc); + hdr.channels ().insert ( + cname, + Channel (HALF, 1, 1)); + } + } { FrameBuffer fb; @@ -104,7 +116,10 @@ writeRead ( 1) // ySampling ); - cout << "writing" << flush; + if (manyC) + cout << "Many Channels: writing" << flush; + else + cout << "Values: writing" << flush; remove (fileName); OutputFile out (fileName, hdr); @@ -213,6 +228,41 @@ writeRead ( assert (h4in[y][x] == 3.0); } } + + if (manyC) + { + for ( int curc = 0; curc < 132; ++curc ) + { + char cname[32]; + snprintf (cname, 32, "c%03d", curc); + + cout << " " << curc << flush; + Array2D testcin (h, w); + + FrameBuffer fb; + + /* if the channel isn't there, will fill with 3 but we should have 0 */ + fb.insert ( + cname, // name + Slice ( + HALF, // type + (char*) &testcin[-dy][-dx], // base + sizeof (testcin[0][0]), // xStride + sizeof (testcin[0][0]) * w, // yStride + 1, 1, 3.0) + ); + + in.setFrameBuffer (fb); + in.readPixels (dw.min.y, dw.max.y); + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + assert (testcin[y][x] == 0.0); + } + } + } + } } remove (fileName); @@ -306,7 +356,8 @@ testChannels (const std::string& tempDir) std::string filename = tempDir + "imf_test_channels.exr"; - writeRead (ph1, ph2, filename.c_str (), W, H); + writeRead (ph1, ph2, filename.c_str (), W, H, false); + writeRead (ph1, ph2, filename.c_str (), W, H, true); cout << "ok\n" << endl; } From c07a0f1ee662233500335a9cb713f73e0de0af3d Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 13 Jul 2026 20:11:54 -0700 Subject: [PATCH 52/63] Reject NO_COMPRESSION scanline chunks with short packed size. (#2548) Mirror the existing tile-path check in exr_read_scanline_chunk_info(): for EXR_COMPRESSION_NONE, require packed_size to equal unpacked_size before decode allocates an unpack buffer that no decompressor fills. Covers flat and deep scanline chunk leaders. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-7hgm-jxjc-6hgg Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-fwhm-jj7c-mx7v Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXRCore/chunk.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lib/OpenEXRCore/chunk.c b/src/lib/OpenEXRCore/chunk.c index b4f79a498..d7e098605 100644 --- a/src/lib/OpenEXRCore/chunk.c +++ b/src/lib/OpenEXRCore/chunk.c @@ -1120,6 +1120,17 @@ exr_read_scanline_chunk_info ( if (cinfo->packed_size == 0 && cinfo->unpacked_size > 0) return ctxt->report_error ( ctxt, EXR_ERR_INVALID_ARGUMENT, "Invalid packed size of 0"); + + if (part->comp_type == EXR_COMPRESSION_NONE && + cinfo->packed_size != cinfo->unpacked_size) + { + return ctxt->print_error ( + ctxt, + EXR_ERR_BAD_CHUNK_LEADER, + "Mismatch between unpacked and packed size with uncompressed data: packed is %" PRIu64 "; unpacked is %" PRIu64, + cinfo->packed_size, cinfo->unpacked_size); + } + return EXR_ERR_SUCCESS; } From 783b654273bf6cba2ca17f6a348395cb41f0fe74 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 13 Jul 2026 20:12:29 -0700 Subject: [PATCH 53/63] Reject short zlib inflates before pixel unpack. (#2547) DWA UNKNOWN: pass actual_out to exr_uncompress_buffer() and require the inflated byte count to match UNKNOWN_UNCOMPRESSED_SIZE before copying planar data to output rows. ZIP/ZIPS: require actual_out_bytes to equal the expected uncompressed chunk size before reconstructing and unpacking pixels. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-38j8-88v6-jrm7 Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-r864-gwqv-q2hp Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXRCore/internal_dwa_compressor.h | 17 ++++++++++------- src/lib/OpenEXRCore/internal_zip.c | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/lib/OpenEXRCore/internal_dwa_compressor.h b/src/lib/OpenEXRCore/internal_dwa_compressor.h index e9b712352..1fe256e4b 100644 --- a/src/lib/OpenEXRCore/internal_dwa_compressor.h +++ b/src/lib/OpenEXRCore/internal_dwa_compressor.h @@ -873,18 +873,21 @@ DwaCompressor_uncompress ( if (unknownCompressedSize > 0) { + size_t actualUnknown; + if (unknownUncompressedSize > me->_planarUncBufferSize[UNKNOWN]) { return EXR_ERR_CORRUPT_CHUNK; } - if (EXR_ERR_SUCCESS != exr_uncompress_buffer ( - me->_decode->context, - compressedUnknownBuf, - unknownCompressedSize, - me->_planarUncBuffer[UNKNOWN], - unknownUncompressedSize, - NULL)) + rv = exr_uncompress_buffer ( + me->_decode->context, + compressedUnknownBuf, + unknownCompressedSize, + me->_planarUncBuffer[UNKNOWN], + unknownUncompressedSize, + &actualUnknown); + if (rv != EXR_ERR_SUCCESS || actualUnknown != unknownUncompressedSize) { return EXR_ERR_CORRUPT_CHUNK; } diff --git a/src/lib/OpenEXRCore/internal_zip.c b/src/lib/OpenEXRCore/internal_zip.c index f7aa6433f..5fd5eef8c 100644 --- a/src/lib/OpenEXRCore/internal_zip.c +++ b/src/lib/OpenEXRCore/internal_zip.c @@ -313,7 +313,7 @@ undo_zip_impl ( if (res == EXR_ERR_SUCCESS) { decode->bytes_decompressed = actual_out_bytes; - if (comp_buf_size > actual_out_bytes || actual_out_bytes > uncompressed_size) + if (actual_out_bytes != uncompressed_size) res = EXR_ERR_CORRUPT_CHUNK; else internal_zip_reconstruct_bytes ( From c33a00625ac329b8330ff01ccf77b548a78ecb0c Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 13 Jul 2026 20:13:03 -0700 Subject: [PATCH 54/63] Reject oversized channelstore allocations in exrmultipart convert (#2541) The convert path computed pixel_count as int64_t but passed samplesize * pixel_count to std::vector::resize(size_type), which truncates on ILP32 and left readPixels() writing past the buffer. Validate the size fits in size_t before resizing channelstore. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-r24r-74rc-588f Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/bin/exrmultipart/exrmultipart.cpp | 29 ++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/bin/exrmultipart/exrmultipart.cpp b/src/bin/exrmultipart/exrmultipart.cpp index 885197dc6..7c5fc8f03 100644 --- a/src/bin/exrmultipart/exrmultipart.cpp +++ b/src/bin/exrmultipart/exrmultipart.cpp @@ -32,7 +32,9 @@ #include #include #include +#include #include +#include #include #include #include // pair @@ -51,6 +53,31 @@ using namespace OPENEXR_IMF_NAMESPACE; # define IMF_PATH_SEPARATOR "/" #endif +namespace { + +// +// Validate that count * samplesize fits in size_t before resizing a vector. +// + +size_t +vectorSize (int64_t count, size_t samplesize) +{ + if (count < 0) + throw IEX_NAMESPACE::OverflowExc ("invalid vector size"); + + const size_t size_t_max = std::numeric_limits::max (); + if (sizeof (size_t) < sizeof (int64_t) && count > static_cast (size_t_max)) + throw IEX_NAMESPACE::OverflowExc ("invalid vector size"); + + const size_t c = static_cast (count); + if (samplesize > 0 && c > size_t_max / samplesize) + throw IEX_NAMESPACE::OverflowExc ("invalid vector size"); + + return c * samplesize; +} + +} // namespace + void copy_tile ( MultiPartInputFile& input, @@ -323,7 +350,7 @@ convert ( // compute size of channel size_t samplesize = sizeof (float); if (chan.channel ().type == HALF) { samplesize = sizeof (half); } - channelstore[i].resize (samplesize * pixel_count); + channelstore[i].resize (vectorSize (pixel_count, samplesize)); output_framebuffers[part].insert ( output_channels[i].name, From 04c52e7371b3fd771035a25511da3793f03afe16 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 13 Jul 2026 20:13:29 -0700 Subject: [PATCH 55/63] Reject oversized Array2D allocations on ILP32 (#2540) Array2D computed sizeX * sizeY in 32-bit arithmetic before new[]. On ILP32, a 65537 x 65537 allocation wraps to a tiny buffer while decode still writes the full image. Validate the element count in uint64_t and reject dimensions whose product exceeds size_t before constructing or resizing Array2D. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-h56j-j82x-w3fp Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-wrw5-mm52-r3h8 Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/lib/OpenEXR/ImfArray.h | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/lib/OpenEXR/ImfArray.h b/src/lib/OpenEXR/ImfArray.h index 395fc67e5..2182120e0 100644 --- a/src/lib/OpenEXR/ImfArray.h +++ b/src/lib/OpenEXR/ImfArray.h @@ -8,8 +8,11 @@ #include "ImfForward.h" #include "IexBaseExc.h" +#include "IexMathExc.h" #include +#include +#include //------------------------------------------------------------------------- // @@ -160,6 +163,21 @@ template class IMF_EXPORT_TEMPLATE_TYPE Array2D // Implementation //--------------- +namespace { + +inline size_t +array2DElementCount (long sizeX, long sizeY) +{ + const uint64_t x = static_cast (sizeX); + const uint64_t y = static_cast (sizeY); + const uint64_t maxSize = std::numeric_limits::max (); + if (y > 0 && x > maxSize / y) + throw IEX_NAMESPACE::OverflowExc ("Array2D dimensions too large"); + return static_cast (x * y); +} + +} // namespace + template inline void Array::resizeErase (long size) @@ -202,7 +220,7 @@ inline Array2D::Array2D (long sizeX, long sizeY) _sizeX = sizeX; _sizeY = sizeY; - _data = new T[(size_t) sizeX * (size_t) sizeY]; + _data = new T[array2DElementCount (sizeX, sizeY)]; } template inline Array2D::~Array2D () @@ -231,7 +249,7 @@ Array2D::resizeErase (long sizeX, long sizeY) if (sizeX < 0 || sizeY < 0) throw IEX_NAMESPACE::ArgExc ("Array2D dimensions must be non-negative"); - T* tmp = new T[(size_t) sizeX * (size_t) sizeY]; + T* tmp = new T[array2DElementCount (sizeX, sizeY)]; delete[] _data; _sizeX = sizeX; _sizeY = sizeY; @@ -249,7 +267,7 @@ Array2D::resizeEraseUnsafe (long sizeX, long sizeY) _data = 0; _sizeX = 0; _sizeY = 0; - _data = new T[(size_t) sizeX * (size_t) sizeY]; + _data = new T[array2DElementCount (sizeX, sizeY)]; _sizeX = sizeX; _sizeY = sizeY; } From 55888dbd69f9e9edfc5495934fbfa4db37f474b1 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Mon, 13 Jul 2026 20:13:58 -0700 Subject: [PATCH 56/63] Reject oversized exrmetrics vector allocations on ILP32 (#2539) exrmetrics computed image buffer sizes as uint64_t but passed them to std::vector::resize(size_type), which silently truncates on 32-bit builds and left decode writing past undersized channel and sample-count buffers. Validate count and size to confirm the cast to size_t does not overflow. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-r8mj-rhfc-38g4 Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-pgc2-hppj-q623 Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-g5m8-8w79-34q8 Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-xc77-xm9h-qxm4 Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/bin/exrmetrics/exrmetrics.cpp | 32 +++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/bin/exrmetrics/exrmetrics.cpp b/src/bin/exrmetrics/exrmetrics.cpp index 46c19a7ba..776ae22f4 100644 --- a/src/bin/exrmetrics/exrmetrics.cpp +++ b/src/bin/exrmetrics/exrmetrics.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -46,6 +47,25 @@ using std::vector; using std::chrono::steady_clock; using std::isinf; +namespace { + +// +// Validate that count*sampleSize casts to size_t without overflow, before +// using the value to resize a std::vector. +// + +size_t +vectorSize (uint64_t count, int sampleSize = 1) +{ + const uint64_t sampleSizeU = static_cast (sampleSize); + const uint64_t maxSize = std::numeric_limits::max (); + if (sampleSizeU > 0 && count > maxSize / sampleSizeU) + throw IEX_NAMESPACE::OverflowExc ("Integer multiplication overflow."); + return static_cast (count * sampleSizeU); +} + +} // namespace + double timing (steady_clock::time_point start, steady_clock::time_point end) { @@ -92,7 +112,7 @@ initScanLine ( size_t pixelsInChannel = (width / i.channel ().xSampling) * (height / i.channel ().ySampling); rawSize += pixelsInChannel * samplesize; - pixelData[channelNumber].resize (numPixels * samplesize); + pixelData[channelNumber].resize (vectorSize (numPixels, samplesize)); buf.insert ( i.name (), @@ -205,7 +225,7 @@ initTiled ( { int samplesize = pixelTypeSize (i.channel ().type); pixelData[levelIndex][channelNumber].resize ( - numPixels * samplesize); + vectorSize (numPixels, samplesize)); buf[levelIndex].insert ( i.name (), @@ -324,7 +344,7 @@ initAndReadDeepScanLine ( uint64_t height = dw.max.y + 1 - dw.min.y; uint64_t numPixels = width * height; int numChans = channelCount (in.header ()); - sampleCount.resize (numPixels); + sampleCount.resize (vectorSize (numPixels)); uint64_t offsetToOrigin = width * static_cast (dw.min.y) + static_cast (dw.min.x); @@ -342,7 +362,7 @@ initAndReadDeepScanLine ( i != outHeader.channels ().end (); ++i) { - pixelPtrs[channelNumber].resize (numPixels); + pixelPtrs[channelNumber].resize (vectorSize (numPixels)); int samplesize = pixelTypeSize (i.channel ().type); buf.insert ( i.name (), @@ -492,7 +512,7 @@ initAndReadDeepTiled ( static_cast (dw.min.x); pixelPtrs.resize (numChans); - sampleCount.resize (numPixels); + sampleCount.resize (vectorSize (numPixels)); buf.insertSampleCountSlice (Slice ( UINT, @@ -506,7 +526,7 @@ initAndReadDeepTiled ( i != outHeader.channels ().end (); ++i) { - pixelPtrs[channelNumber].resize (numPixels); + pixelPtrs[channelNumber].resize (vectorSize (numPixels)); int samplesize = pixelTypeSize (i.channel ().type); buf.insert ( i.name (), From b2ed287077af3b01194f116d4acc99687f89f9ea Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Tue, 14 Jul 2026 08:38:00 -0700 Subject: [PATCH 57/63] Fix missing INT_MAX cap on deep scanline sample_count_table_size (#2535) ddata[1] (packed_size) and ddata[2] (unpacked_size) both had '< 0 || > INT_MAX' guards, but ddata[0] (sample_count_table_size) only had '< 0'. A value > INT_MAX stored in the uint64_t field then gets truncated to size_t on ILP32, causing an undersized allocation followed by a heap overflow when exr_read_deep_chunk writes the full 64-bit byte count into it. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-m5cq-cx25-qw53 Signed-off-by: Cary Phillips Co-authored-by: Claude Sonnet 4.6 --- src/lib/OpenEXRCore/chunk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/OpenEXRCore/chunk.c b/src/lib/OpenEXRCore/chunk.c index d7e098605..f8ab3e9d6 100644 --- a/src/lib/OpenEXRCore/chunk.c +++ b/src/lib/OpenEXRCore/chunk.c @@ -1006,7 +1006,7 @@ exr_read_scanline_chunk_info ( if (rv != EXR_ERR_SUCCESS) { return rv; } priv_to_native64 (ddata, 3); - if (ddata[0] < 0) + if (ddata[0] < 0 || ddata[0] > (int64_t) INT_MAX) { return ctxt->print_error ( ctxt, From 606394eb6fc8709ef76c5bf80ec0476a1cc4b8d6 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Tue, 14 Jul 2026 20:22:39 -0700 Subject: [PATCH 58/63] Fix broken links identified in ASWF Health Check 2026 (#2549) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit README.md: CODE_OF_CONDUCT → CODE_OF_CONDUCT.md CONTRIBUTING.md: - website/requirements.txtg → website/requirements.txt - #Creating-a-Major/Minor-Release → #creating-a-majorminor-release - #required-approvals → #code-review-and-required-approvals Signed-off-by: Cary Phillips Co-authored-by: Claude Sonnet 4.6 --- CONTRIBUTING.md | 6 +++--- README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5e9518a31..9225172a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ explains our contribution process and procedures: * [Versioning Policy](#Versioning-Policy) * [Contributing to the Website](#Contributing-to-the-Website) * [Creating a Patch Release](#Creating-a-Patch-Release) -* [Creating a Major/Minor Release](#Creating-a-Major/Minor-Release) +* [Creating a Major/Minor Release](#creating-a-majorminor-release) For a description of the roles and responsibilities of the various members of the OpenEXR community, see [GOVERNANCE](GOVERNANCE.md), and @@ -241,7 +241,7 @@ who may discuss, offer constructive feedback, request changes, or approve the work. 6. Upon receiving the required number of committer approvals (as -outlined in [Required Approvals](#required-approvals)), a committer +outlined in [Required Approvals](#code-review-and-required-approvals)), a committer other than the PR contributor may merge changes into the ``main`` branch. @@ -479,7 +479,7 @@ target. Generation is off by default. Building the website requires that ``sphinx``, ``breathe``, and ``doxygen`` are installed. It further requires the [sphinx-press-theme] (https://pypi.org/project/sphinx-press-theme). Complete dependencies -are described in the [requirements.txt](website/requirements.txtg) +are described in the [requirements.txt](website/requirements.txt) file. On Debian/Ubuntu Linux: diff --git a/README.md b/README.md index 7c9ec6960..501e8084b 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ package. OpenEXR is a project of the [Academy Software Foundation](https://www.aswf.io). See the project's [governance -policies](GOVERNANCE.md), [contribution guidelines](CONTRIBUTING.md), and [code of conduct](CODE_OF_CONDUCT) +policies](GOVERNANCE.md), [contribution guidelines](CONTRIBUTING.md), and [code of conduct](CODE_OF_CONDUCT.md) for more information. # Building OpenEXR From 4da0b2033cc45ed331fdabcc70b314fbac49a3ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:17:05 -0700 Subject: [PATCH 59/63] Bump vmactions/freebsd-vm from 1.5.0 to 1.5.2 (#2552) Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm) from 1.5.0 to 1.5.2. - [Release notes](https://github.com/vmactions/freebsd-vm/releases) - [Commits](https://github.com/vmactions/freebsd-vm/compare/5a72679103d223925653750faa878a143340fbd0...77ed28d336d03fe19a3f4f7266c1d2c4714dd79d) --- updated-dependencies: - dependency-name: vmactions/freebsd-vm dependency-version: 1.5.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci_freebsd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_freebsd.yml b/.github/workflows/ci_freebsd.yml index f51f48e6a..0bd2f3167 100644 --- a/.github/workflows/ci_freebsd.yml +++ b/.github/workflows/ci_freebsd.yml @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Build and test on FreeBSD - uses: vmactions/freebsd-vm@5a72679103d223925653750faa878a143340fbd0 # v1.5.0 + uses: vmactions/freebsd-vm@77ed28d336d03fe19a3f4f7266c1d2c4714dd79d # v1.5.2 with: release: '15.0' envs: GITHUB_REPOSITORY GITHUB_REF GITHUB_SHA From 3b17297f5d2da237cf1392f632b04f3de0999303 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:17:29 -0700 Subject: [PATCH 60/63] Bump the codeql group with 3 updates (#2551) Bumps the codeql group with 3 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action). Updates `github/codeql-action/init` from 4.37.0 to 4.37.1 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a) Updates `github/codeql-action/analyze` from 4.37.0 to 4.37.1 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a) Updates `github/codeql-action/upload-sarif` from 4.37.0 to 4.37.1 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql - dependency-name: github/codeql-action/analyze dependency-version: 4.37.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.37.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: codeql ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index cf6b105f0..1915e2aa2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -68,7 +68,7 @@ jobs: # cary: Pin the version to the SHA for 2.18.0, since there appears to # be a problem with 2.18.1 leading to a "No space left on # device" failure - uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: # cary: the "linked" setting is necessary to force the run to pick up # the version specified in the action. @@ -99,7 +99,7 @@ jobs: - name: Perform CodeQL Analysis # Pin the version to the SHA for 2.18.0 - uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: category: "/language:${{matrix.language}}" # For pull_request, upload against refs/pull//head + head SHA so the Code diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 743b1502e..4ea86d94e 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -54,6 +54,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: sarif_file: results.sarif From fb6b3d0593b427ea100c291724b36a34c5d075a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:18:01 -0700 Subject: [PATCH 61/63] Bump pypa/gh-action-pypi-publish from 1.14.0 to 1.14.1 (#2553) Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.14.0 to 1.14.1. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/cef221092ed1bacb1cc03d23a2d87d1d172e277b...ba38be9e461d3875417946c167d0b5f3d385a247) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-version: 1.14.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/python-wheels-publish-test.yml | 2 +- .github/workflows/python-wheels-publish.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-wheels-publish-test.yml b/.github/workflows/python-wheels-publish-test.yml index 57b9c089d..024e80109 100644 --- a/.github/workflows/python-wheels-publish-test.yml +++ b/.github/workflows/python-wheels-publish-test.yml @@ -139,6 +139,6 @@ jobs: path: dist - name: Publish distribution 📦 to TestPyPI - uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 + uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1 with: repository-url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/python-wheels-publish.yml b/.github/workflows/python-wheels-publish.yml index 92bc65af1..9dd43c0ad 100644 --- a/.github/workflows/python-wheels-publish.yml +++ b/.github/workflows/python-wheels-publish.yml @@ -132,4 +132,4 @@ jobs: path: dist - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 + uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1 From a42794341a3b2435dc5877460a221a9b64b14e8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:18:47 -0700 Subject: [PATCH 62/63] Bump actions/setup-python from 6.3.0 to 7.0.0 (#2554) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.3.0 to 7.0.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/ece7cb06caefa5fff74198d8649806c4678c61a1...5fda3b95a4ea91299a34e894583c3862153e4b97) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cary Phillips --- .github/workflows/python-wheels-publish-test.yml | 2 +- .github/workflows/python-wheels-publish.yml | 2 +- .github/workflows/python-wheels.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/python-wheels-publish-test.yml b/.github/workflows/python-wheels-publish-test.yml index 024e80109..d69f7d159 100644 --- a/.github/workflows/python-wheels-publish-test.yml +++ b/.github/workflows/python-wheels-publish-test.yml @@ -81,7 +81,7 @@ jobs: - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: '3.x' diff --git a/.github/workflows/python-wheels-publish.yml b/.github/workflows/python-wheels-publish.yml index 9dd43c0ad..1b0373e10 100644 --- a/.github/workflows/python-wheels-publish.yml +++ b/.github/workflows/python-wheels-publish.yml @@ -77,7 +77,7 @@ jobs: - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: '3.x' diff --git a/.github/workflows/python-wheels.yml b/.github/workflows/python-wheels.yml index 10d841e40..081b77375 100644 --- a/.github/workflows/python-wheels.yml +++ b/.github/workflows/python-wheels.yml @@ -65,7 +65,7 @@ jobs: - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: '3.x' From 3f0f6c2d556a9b547cc8fd83f07018394a61a019 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:19:34 -0700 Subject: [PATCH 63/63] Bump actions/checkout from 7.0.0 to 7.0.1 (#2555) Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/analysis_workflow.yml | 6 +++--- .github/workflows/bazel_build.yml | 6 +++--- .github/workflows/ci_steps.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/python-wheels-publish-test.yml | 4 ++-- .github/workflows/python-wheels-publish.yml | 4 ++-- .github/workflows/python-wheels.yml | 2 +- .github/workflows/release-sign.yml | 2 +- .github/workflows/scorecard.yml | 2 +- .github/workflows/snyk-scan-cron.yml | 2 +- .github/workflows/website.yml | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/analysis_workflow.yml b/.github/workflows/analysis_workflow.yml index 74afface2..cb8582d80 100644 --- a/.github/workflows/analysis_workflow.yml +++ b/.github/workflows/analysis_workflow.yml @@ -35,7 +35,7 @@ jobs: CC: gcc steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 50 - name: Create build directories @@ -105,7 +105,7 @@ jobs: - name: Setup container run: sudo rm -rf /usr/local/lib64/cmake/glew - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 50 - name: Create build directories @@ -184,7 +184,7 @@ jobs: - name: Setup container run: sudo rm -rf /usr/local/lib64/cmake/glew - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 50 - name: Create build directories diff --git a/.github/workflows/bazel_build.yml b/.github/workflows/bazel_build.yml index dc8b85134..e9d25d15e 100644 --- a/.github/workflows/bazel_build.yml +++ b/.github/workflows/bazel_build.yml @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Mount Bazel cache uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 @@ -57,7 +57,7 @@ jobs: runs-on: windows-2025 steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Mount Bazel cache uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 @@ -75,7 +75,7 @@ jobs: runs-on: macos-15 steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Mount Bazel cache uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 diff --git a/.github/workflows/ci_steps.yml b/.github/workflows/ci_steps.yml index cd491e841..bf4472947 100644 --- a/.github/workflows/ci_steps.yml +++ b/.github/workflows/ci_steps.yml @@ -88,7 +88,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set Up Directories & Environment run: | diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1915e2aa2..545d0d28d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -61,7 +61,7 @@ jobs: # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/python-wheels-publish-test.yml b/.github/workflows/python-wheels-publish-test.yml index d69f7d159..3fee06aea 100644 --- a/.github/workflows/python-wheels-publish-test.yml +++ b/.github/workflows/python-wheels-publish-test.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 ref: ${{ github.ref }} @@ -77,7 +77,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} diff --git a/.github/workflows/python-wheels-publish.yml b/.github/workflows/python-wheels-publish.yml index 1b0373e10..5dd299543 100644 --- a/.github/workflows/python-wheels-publish.yml +++ b/.github/workflows/python-wheels-publish.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 ref: ${{ github.event_name == 'release' && github.event.release.tag_name || github.ref }} @@ -73,7 +73,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} diff --git a/.github/workflows/python-wheels.yml b/.github/workflows/python-wheels.yml index 081b77375..8154629d8 100644 --- a/.github/workflows/python-wheels.yml +++ b/.github/workflows/python-wheels.yml @@ -61,7 +61,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Python if: ${{ matrix.os == 'ubuntu-latest' }} diff --git a/.github/workflows/release-sign.yml b/.github/workflows/release-sign.yml index a24953d6f..726847081 100644 --- a/.github/workflows/release-sign.yml +++ b/.github/workflows/release-sign.yml @@ -55,7 +55,7 @@ jobs: shell: bash - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 4ea86d94e..618cc9631 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -28,7 +28,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false diff --git a/.github/workflows/snyk-scan-cron.yml b/.github/workflows/snyk-scan-cron.yml index 513e1bb70..23de3209d 100644 --- a/.github/workflows/snyk-scan-cron.yml +++ b/.github/workflows/snyk-scan-cron.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'AcademySoftwareFoundation/openexr' steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: snyk/actions/setup@9adf32b1121593767fc3c057af55b55db032dc04 # v1.0.0 id: snyk diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 20611035f..658b6bbd5 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -54,7 +54,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Create build directory run: mkdir _build - name: Install doxygen