From 54ba4db542ad3c7b918812a4e2d69c27735a3199 Mon Sep 17 00:00:00 2001
From: Andrew Murray <3112309+radarhere@users.noreply.github.com>
Date: Wed, 11 Feb 2026 10:24:50 +1100
Subject: [PATCH] Fix OOB Write with invalid tile extents (#9427)

Co-authored-by: Eric Soroos <eric-github@soroos.net>
---
 Tests/test_imagefile.py          |   7 +++++++
 src/decode.c                     |   3 ++-
 src/encode.c                     |   3 ++-
 9 files changed, 53 insertions(+), 2 deletions(-)

Index: pillow-11.3.0/Tests/test_imagefile.py
===================================================================
--- pillow-11.3.0.orig/Tests/test_imagefile.py
+++ pillow-11.3.0/Tests/test_imagefile.py
@@ -169,6 +169,13 @@ class TestImageFile:
         with pytest.raises(OSError):
             p.close()
 
+    @pytest.mark.parametrize("xy", ((-1, 0), (0, -1)))
+    def test_negative_tile_extents(self, xy: tuple[int, int]) -> None:
+        im = Image.new("1", (1, 1))
+        fp = BytesIO()
+        with pytest.raises(SystemError, match="tile cannot extend outside image"):
+            ImageFile._save(im, fp, [ImageFile._Tile("raw", xy + (1, 1), 0, "1")])
+
     def test_no_format(self) -> None:
         buf = BytesIO(b"\x00" * 255)
 
Index: pillow-11.3.0/src/decode.c
===================================================================
--- pillow-11.3.0.orig/src/decode.c
+++ pillow-11.3.0/src/decode.c
@@ -186,7 +186,8 @@ _setimage(ImagingDecoderObject *decoder,
         state->ysize = y1 - y0;
     }
 
-    if (state->xsize <= 0 || state->xsize + state->xoff > (int)im->xsize ||
+    if (state->xoff < 0 || state->xsize <= 0 ||
+        state->xsize + state->xoff > (int)im->xsize || state->yoff < 0 ||
         state->ysize <= 0 || state->ysize + state->yoff > (int)im->ysize) {
         PyErr_SetString(PyExc_ValueError, "tile cannot extend outside image");
         return NULL;
Index: pillow-11.3.0/src/encode.c
===================================================================
--- pillow-11.3.0.orig/src/encode.c
+++ pillow-11.3.0/src/encode.c
@@ -254,7 +254,8 @@ _setimage(ImagingEncoderObject *encoder,
         state->ysize = y1 - y0;
     }
 
-    if (state->xsize <= 0 || state->xsize + state->xoff > im->xsize ||
+    if (state->xoff < 0 || state->xsize <= 0 ||
+        state->xsize + state->xoff > im->xsize || state->yoff < 0 ||
         state->ysize <= 0 || state->ysize + state->yoff > im->ysize) {
         PyErr_SetString(PyExc_SystemError, "tile cannot extend outside image");
         return NULL;
