From c98a51d2f9554964670a0ad7dac0c6188f18b146 Mon Sep 17 00:00:00 2001
From: Andrew Murray <radarhere@users.noreply.github.com>
Date: Fri, 6 Mar 2026 10:22:26 +1100
Subject: [PATCH] Raise an error if the trailer chain loops back on itself

---
 Tests/images/trailer_loop.pdf | Bin 0 -> 1818 bytes
 Tests/test_pdfparser.py       |   5 +++++
 src/PIL/PdfParser.py          |  10 ++++++++--
 3 files changed, 13 insertions(+), 2 deletions(-)
 create mode 100644 Tests/images/trailer_loop.pdf

Index: Pillow-9.5.0/Tests/test_pdfparser.py
===================================================================
--- Pillow-9.5.0.orig/Tests/test_pdfparser.py
+++ Pillow-9.5.0/Tests/test_pdfparser.py
@@ -117,3 +117,8 @@ def test_pdf_repr():
     assert pdf_repr(b"a)/b\\(c") == rb"(a\)/b\\\(c)"
     assert pdf_repr([123, True, {"a": PdfName(b"b")}]) == b"[ 123 true <<\n/a /b\n>> ]"
     assert pdf_repr(PdfBinary(b"\x90\x1F\xA0")) == b"<901FA0>"
+
+
+def test_trailer_loop() -> None:
+    with pytest.raises(PdfFormatError, match="trailer loop found"):
+        PdfParser("Tests/images/trailer_loop.pdf")
Index: Pillow-9.5.0/src/PIL/PdfParser.py
===================================================================
--- Pillow-9.5.0.orig/src/PIL/PdfParser.py
+++ Pillow-9.5.0/src/PIL/PdfParser.py
@@ -636,7 +636,7 @@ class PdfParser:
         if b"Prev" in self.trailer_dict:
             self.read_prev_trailer(self.trailer_dict[b"Prev"])
 
-    def read_prev_trailer(self, xref_section_offset):
+    def read_prev_trailer(self, xref_section_offset, processed_offsets=None):
         trailer_offset = self.read_xref_table(xref_section_offset=xref_section_offset)
         m = self.re_trailer_prev.search(
             self.buf[trailer_offset : trailer_offset + 16384]
@@ -649,7 +649,12 @@ class PdfParser:
         )
         trailer_dict = self.interpret_trailer(trailer_data)
         if b"Prev" in trailer_dict:
-            self.read_prev_trailer(trailer_dict[b"Prev"])
+            processed_offsets = processed_offsets or []
+            processed_offsets.append(xref_section_offset)
+            check_format_condition(
+                trailer_dict[b"Prev"] not in processed_offsets, "trailer loop found"
+            )
+            self.read_prev_trailer(trailer_dict[b"Prev"], processed_offsets)
 
     re_whitespace_optional = re.compile(whitespace_optional)
     re_name = re.compile(
