From 3367144d502c2e61cb51d3c52885901e7948c39b Mon Sep 17 00:00:00 2001 From: BukeLy Date: Thu, 16 Jul 2026 18:44:01 +0800 Subject: [PATCH] fix(security): validate TOC identity before index updates --- pageindex/page_index.py | 6 ++++++ tests/test_page_index.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 tests/test_page_index.py diff --git a/pageindex/page_index.py b/pageindex/page_index.py index 235144b..8afe4a6 100644 --- a/pageindex/page_index.py +++ b/pageindex/page_index.py @@ -761,6 +761,12 @@ def process_toc_no_page_numbers(toc_content, toc_page_list, page_list, start_in raise ValueError( "LLM returned a different number of TOC entries than expected." ) + if any( + (update.get("structure"), update.get("title")) + != (current.get("structure"), current.get("title")) + for update, current in zip(llm_result, toc_with_page_number) + ): + raise ValueError("LLM returned reordered or modified TOC entries.") valid_indices = _extract_chunk_marker_set(group_text) for idx, current in enumerate(toc_with_page_number): diff --git a/tests/test_page_index.py b/tests/test_page_index.py new file mode 100644 index 0000000..4c3631a --- /dev/null +++ b/tests/test_page_index.py @@ -0,0 +1,32 @@ +import unittest +from unittest.mock import Mock, patch + +from pageindex.page_index import process_toc_no_page_numbers + + +class ProcessTocNoPageNumbersTest(unittest.TestCase): + def test_rejects_same_length_reordered_llm_toc(self): + toc = [ + {"structure": "1", "title": "First"}, + {"structure": "2", "title": "Second"}, + ] + reordered = [ + {"structure": "2", "title": "Second", "physical_index": ""}, + {"structure": "1", "title": "First", "physical_index": ""}, + ] + + with patch("pageindex.page_index.toc_transformer", return_value=toc), \ + patch("pageindex.page_index.count_tokens", return_value=1), \ + patch("pageindex.page_index.page_list_to_group_text", return_value=[" "]), \ + patch("pageindex.page_index.add_page_number_to_toc", return_value=reordered): + with self.assertRaises(ValueError): + process_toc_no_page_numbers( + "toc", + [], + [["page one"], ["page two"]], + logger=Mock(), + ) + + +if __name__ == "__main__": + unittest.main()