diff --git a/meta-python/recipes-devtools/python/python3-pillow/CVE-2026-112393.patch b/meta-python/recipes-devtools/python/python3-pillow/CVE-2026-112393.patch
new file mode 100644
index 0000000000..cb9be3b33e
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-pillow/CVE-2026-112393.patch
@@ -0,0 +1,124 @@
+From 9b693ea929423da2bebef5523881ae3850c3877e Mon Sep 17 00:00:00 2001
+From: Jeffrey 'Alex' Clark <aclark@aclark.net>
+Date: Mon, 12 Oct 2026 21:18:41 -0400
+Subject: [PATCH] Fix heap buffer overflow in _tiffWriteProc when saving TIFF
+ to BytesIO
+
+libtiff seeks past the current end of data when writing the directory
+and writes tag values there. _tiffWriteProc sized its realloc() from
+state->size + size instead of the write position state->loc + size,
+so the first out-of-line tag value written after such a seek could
+overrun the allocation by up to the size of the directory. The bytes
+skipped by the seek were also never zeroed, leaking stale heap
+contents into the saved file.
+
+Size the buffer from the write position and zero the space added by
+realloc, matching the semantics of writing to a real file. Reject
+writes where the position is still beyond the buffer for the
+non-reallocating case.
+
+Reported-by: carlini
+Reported-by: Tomer-PL
+Fixes: GHSA-332p-7hrc-92wf
+
+Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
+Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
+
+CVE: CVE-2026-112393
+Upstream-Status: Backport [https://github.com/python-pillow/Pillow/commit/78c08bd4d9c08037f77465a61d90633f669013f4]
+
+Signed-off-by: Kris Gavvala <kris.gavvala@windriver.com>
+---
+ Tests/test_file_libtiff.py  | 36 ++++++++++++++++++++++++++++++++++++
+ src/libImaging/TiffDecode.c | 15 ++++++++++++++-
+ 2 files changed, 50 insertions(+), 1 deletion(-)
+
+diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py
+index c9849a056..84e4299a1 100644
+--- a/Tests/test_file_libtiff.py
++++ b/Tests/test_file_libtiff.py
+@@ -757,6 +757,42 @@ class TestFileLibTiff(LibTiffTestCase):
+         save_bytesio("packbits")
+         save_bytesio("tiff_lzw")
+ 
++
++    def test_save_bytesio_seek_past_end(self, tmp_path: Path) -> None:
++        # When writing the directory, libtiff seeks past the end of the data
++        # written so far, and then writes the tag values there. Check that the
++        # in-memory write buffer grows to fit, and that the bytes that are
++        # skipped over are zero, as they would be when writing to a file.
++
++        # 7 distinct bytes per row: PackBits emits 8 bytes per row, so the strip
++        # plus the header are exactly 64 KiB, the initial size of the buffer
++        im = Image.new("L", (7, 8191))
++        im.putdata([(i * 37) & 0xFF for i in range(7 * 8191)])
++        kwargs: dict[str, Any] = {
++            "compression": "packbits",
++            "description": "D" * 65535,
++        }
++
++        outfile = tmp_path / "temp.tif"
++        im.save(outfile, **kwargs)
++        buffer_io = io.BytesIO()
++        im.save(buffer_io, format="tiff", **kwargs)
++        assert buffer_io.getvalue() == outfile.read_bytes()
++
++        # odd-length tag values, so that libtiff pads between them. Large enough
++        # that the buffer has to be reallocated
++        im = hopper().resize((300, 300))
++        kwargs = {
++            "compression": "tiff_lzw",
++            "description": "abcdef",
++            "software": "xyz0",
++            "tiffinfo": {315: "artist", 33432: "copyright!"},
++        }
++        im.save(outfile, **kwargs)
++        buffer_io = io.BytesIO()
++        im.save(buffer_io, format="tiff", **kwargs)
++        assert buffer_io.getvalue() == outfile.read_bytes()
++
+     def test_save_ycbcr(self, tmp_path: Path) -> None:
+         im = hopper("YCbCr")
+         outfile = tmp_path / "temp.tif"
+diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c
+index 72e0d7b30..e21327f02 100644
+--- a/src/libImaging/TiffDecode.c
++++ b/src/libImaging/TiffDecode.c
+@@ -88,10 +88,12 @@ _tiffWriteProc(thandle_t hdata, tdata_t buf, tsize_t size) {
+     dump_state(state);
+ 
+     to_write = min(size, state->size - (tsize_t)state->loc);
++    // libtiff may have seeked past the end of the buffer, e.g. when writing the
++    // directory, so the required size is based on the current location.
+     if (state->flrealloc && size > to_write) {
+         tdata_t new_data;
+         tsize_t newsize = state->size;
+-        while (newsize < (size + state->size)) {
++        while (newsize < (size + (tsize_t)state->loc)) {
+             if (newsize > INT_MAX - 64 * 1024) {
+                 return 0;
+             }
+@@ -105,9 +107,20 @@ _tiffWriteProc(thandle_t hdata, tdata_t buf, tsize_t size) {
+             // fail out
+             return 0;
+         }
++        // zero the new space, so that any bytes libtiff seeks over without
++        // writing are 0 in the output, as they would be in a file
++        memset((UINT8 *)new_data + state->size, 0, newsize - state->size);
+         state->data = new_data;
+         state->size = newsize;
+         to_write = size;
++    } else if (to_write < 0) {
++        TIFFError(
++            "_tiffWriteProc",
++            "Invalid Write at loc %" PRIu64 ", size: %" PRIu64,
++            state->loc,
++            (toff_t)state->size
++        );
++        return 0;
+     }
+ 
+     TRACE(("to_write: %d\n", (int)to_write));
+-- 
+2.43.0
+
diff --git a/meta-python/recipes-devtools/python/python3-pillow_12.3.0.bb b/meta-python/recipes-devtools/python/python3-pillow_12.3.0.bb
index 1c6668e53d..e4826da1a6 100644
--- a/meta-python/recipes-devtools/python/python3-pillow_12.3.0.bb
+++ b/meta-python/recipes-devtools/python/python3-pillow_12.3.0.bb
@@ -7,6 +7,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=a6f0ac3777cfc96ded1b825e32ae7c99"
 
 SRC_URI = "git://github.com/python-pillow/Pillow.git;branch=main;protocol=https;tag=${PV} \
            file://0001-support-cross-compiling.patch \
+           file://CVE-2026-112393.patch \
            "
 SRCREV = "bb1d8e8ab8d29048624d96e3ee53cecf7c13d13d"
 
