From 8084c71dfc2b8fa40b181d13807c55466b304920 Mon Sep 17 00:00:00 2001 From: Venish Paneliya <141703684+VenishPaneliya@users.noreply.github.com> Date: Thu, 20 Aug 2026 13:12:51 +0530 Subject: [PATCH 1/2] Raise a truncated chunk error for a short gAMA chunk gAMA carries a single 4-byte gamma value, but chunk_gAMA read it with i32() without first checking the chunk length. A PNG whose gAMA chunk is shorter than 4 bytes raised struct.error, which ImageFile turns into a SyntaxError, so Image.open() reported "cannot identify image file" for a file that is otherwise a perfectly readable PNG. LOAD_TRUNCATED_IMAGES could not rescue it either: sRGB, pHYs, IHDR, acTL, fcTL and fdAT all return the short chunk when it is set and otherwise raise ValueError("Truncated chunk"), but gAMA failed before reaching that logic. Guard it the same way and add gAMA to the existing test_truncated_chunks parametrisation, which already covers the others. --- Tests/test_file_png.py | 2 +- src/PIL/PngImagePlugin.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index f4fe1de013d..b69f6c27827 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -700,7 +700,7 @@ def test_padded_idat(self, monkeypatch: pytest.MonkeyPatch) -> None: assert_image_equal_tofile(im, "Tests/images/bw_gradient.png") @pytest.mark.parametrize( - "cid", (b"IHDR", b"sRGB", b"pHYs", b"acTL", b"fcTL", b"fdAT") + "cid", (b"IHDR", b"gAMA", b"sRGB", b"pHYs", b"acTL", b"fcTL", b"fdAT") ) def test_truncated_chunks( self, cid: bytes, monkeypatch: pytest.MonkeyPatch diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 10ae999a774..0342a4ff4ce 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -521,6 +521,11 @@ def chunk_gAMA(self, pos: int, length: int) -> bytes: # gamma setting assert self.fp is not None s = ImageFile._safe_read(self.fp, length) + if length < 4: + if ImageFile.LOAD_TRUNCATED_IMAGES: + return s + msg = "Truncated gAMA chunk" + raise ValueError(msg) self.im_info["gamma"] = i32(s) / 100000.0 return s From cc1602bf855e248c9f6b2cbf28b98a1b54793960 Mon Sep 17 00:00:00 2001 From: Venish Paneliya <141703684+VenishPaneliya@users.noreply.github.com> Date: Thu, 20 Aug 2026 18:21:24 +0530 Subject: [PATCH 2/2] Raise a truncated chunk error for a short cHRM chunk cHRM holds 8 unsigned ints, so check for the full 32 bytes the same way the other fixed-length chunks do. Unpacking exactly 8 ints from the first 32 bytes also fixes two further cases: a chunk longer than 32 bytes but not a multiple of 4 raised struct.error, because ">{len(s) // 4}I" asked for fewer bytes than the buffer held, and a 36-byte chunk quietly produced 9 chromaticity values instead of 8. --- Tests/test_file_png.py | 3 ++- src/PIL/PngImagePlugin.py | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index b69f6c27827..37936cec58c 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -700,7 +700,8 @@ def test_padded_idat(self, monkeypatch: pytest.MonkeyPatch) -> None: assert_image_equal_tofile(im, "Tests/images/bw_gradient.png") @pytest.mark.parametrize( - "cid", (b"IHDR", b"gAMA", b"sRGB", b"pHYs", b"acTL", b"fcTL", b"fdAT") + "cid", + (b"IHDR", b"gAMA", b"cHRM", b"sRGB", b"pHYs", b"acTL", b"fcTL", b"fdAT"), ) def test_truncated_chunks( self, cid: bytes, monkeypatch: pytest.MonkeyPatch diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 0342a4ff4ce..0571c648135 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -535,7 +535,12 @@ def chunk_cHRM(self, pos: int, length: int) -> bytes: assert self.fp is not None s = ImageFile._safe_read(self.fp, length) - raw_vals = struct.unpack(f">{len(s) // 4}I", s) + if length < 32: + if ImageFile.LOAD_TRUNCATED_IMAGES: + return s + msg = "Truncated cHRM chunk" + raise ValueError(msg) + raw_vals = struct.unpack(">8I", s[:32]) self.im_info["chromaticity"] = tuple(elt / 100000.0 for elt in raw_vals) return s