[Security] Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents #174

Description

@YLChen-007

Advisory Details

Title: Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents

Description:

Summary

An unbounded while loop vulnerability in the toc_transformer function allows an unauthenticated attacker to cause a perpetual Denial of Service (DoS) and rapidly exhaust LLM API credits. By providing a PDF with an intentionally long Table of Contents, the system triggers length-truncated API responses that permanently trap the application into continuously querying the backend LLM API.

Details

The root cause resides in pageindex/page_index.py at line 303 within the toc_transformer() function. The application uses an LLM to structure a raw Table of Contents string into a hierarchical JSON format.
If the LLM's response hits the maximum output token limit (finish_reason == "length"), the application automatically attempts to instruct the model to "continue". Crucially, the while loop lacks any retry counter or iteration limits (unlike the correctly-patched extract_toc_content function which explicitly caps attempts to 5).

Consequently, if the model repeatedly truncates the JSON or rejects the completeness check, the execution falls into an inescapable infinite loop:

whilenot (if_complete=="yes"andfinish_reason=="finished"):
# ... rebuilds prompt and calls ChatGPT_API_with_finish_reasonnew_complete, finish_reason=ChatGPT_API_with_finish_reason(model=model, prompt=prompt)
# ...if_complete=check_if_toc_transformation_is_complete(toc_content, last_complete, model)
# NO ITERATION LIMIT OR BAILOUT CONDITION

PoC

  1. Generate an adversarial PDF with thousands of sections in the TOC (sufficiently large to cause the LLM to truncate output), or set up a Mock OpenAI proxy that forcibly returns finish_reason: "length".
  2. Run the application via the CLI against the malicious PDF:
    python run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
  3. Observe the process forever attempting to complete the TOC, utilizing 100% of a CPU thread and rapidly emitting requests. (In a real production environment, this drastically drains OpenAI API credits).

Log of Evidence

[*] Setting up Mock API environment variables on port 18080
[*] Triggering PageIndex parsing on the malicious PDF...
[*] Executing: python3 run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
[Target] Parsing PDF...
[MockAPI] Returning finish_reason: 'length' (max_output_reached)
[MockAPI] Returning completed: 'no'
[MockAPI] Returning finish_reason: 'length' (max_output_reached)
[MockAPI] Returning completed: 'no'
[MockAPI] Returning finish_reason: 'length' (max_output_reached)
[MockAPI] Returning completed: 'no'
...
[!] The process has been running for over 15 seconds, stuck in the infinite loop.

Impact

This vulnerability allows a complete and unauthenticated Denial of Service (DoS) by causing process hanging and unbounded API usage, resulting in service unavailability and the immediate financial exhaustion of the backend LLM service billing account.

Affected products

  • Ecosystem: python
  • Package name: PageIndex
  • Affected versions: All versions currently in repository (main branch)
  • Patched versions:

Severity

  • Severity: High
  • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Weaknesses

  • CWE: CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop')

Occurrences

PermalinkDescription
pageindex/page_index.py#L303The vulnerable unbounded while loop within toc_transformer failing to cap API retry attempts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
       blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
      }
      } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
      })();
      (function(){
      try {
      var __m = "github.com";
      var __re = new RegExp('^' + "github\\.com" + '
      
      Skip to content

      [Security] Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents #174

      Description

      @YLChen-007

      Advisory Details

      Title: Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents

      Description:

      Summary

      An unbounded while loop vulnerability in the toc_transformer function allows an unauthenticated attacker to cause a perpetual Denial of Service (DoS) and rapidly exhaust LLM API credits. By providing a PDF with an intentionally long Table of Contents, the system triggers length-truncated API responses that permanently trap the application into continuously querying the backend LLM API.

      Details

      The root cause resides in pageindex/page_index.py at line 303 within the toc_transformer() function. The application uses an LLM to structure a raw Table of Contents string into a hierarchical JSON format.
      If the LLM's response hits the maximum output token limit (finish_reason == "length"), the application automatically attempts to instruct the model to "continue". Crucially, the while loop lacks any retry counter or iteration limits (unlike the correctly-patched extract_toc_content function which explicitly caps attempts to 5).

      Consequently, if the model repeatedly truncates the JSON or rejects the completeness check, the execution falls into an inescapable infinite loop:

      whilenot (if_complete=="yes"andfinish_reason=="finished"):
      # ... rebuilds prompt and calls ChatGPT_API_with_finish_reasonnew_complete, finish_reason=ChatGPT_API_with_finish_reason(model=model, prompt=prompt)
      # ...if_complete=check_if_toc_transformation_is_complete(toc_content, last_complete, model)
      # NO ITERATION LIMIT OR BAILOUT CONDITION

      PoC

      1. Generate an adversarial PDF with thousands of sections in the TOC (sufficiently large to cause the LLM to truncate output), or set up a Mock OpenAI proxy that forcibly returns finish_reason: "length".
      2. Run the application via the CLI against the malicious PDF:
        python run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
      3. Observe the process forever attempting to complete the TOC, utilizing 100% of a CPU thread and rapidly emitting requests. (In a real production environment, this drastically drains OpenAI API credits).

      Log of Evidence

      [*] Setting up Mock API environment variables on port 18080
      [*] Triggering PageIndex parsing on the malicious PDF...
      [*] Executing: python3 run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
      [Target] Parsing PDF...
      [MockAPI] Returning finish_reason: 'length' (max_output_reached)
      [MockAPI] Returning completed: 'no'
      [MockAPI] Returning finish_reason: 'length' (max_output_reached)
      [MockAPI] Returning completed: 'no'
      [MockAPI] Returning finish_reason: 'length' (max_output_reached)
      [MockAPI] Returning completed: 'no'
      ...
      [!] The process has been running for over 15 seconds, stuck in the infinite loop.
      

      Impact

      This vulnerability allows a complete and unauthenticated Denial of Service (DoS) by causing process hanging and unbounded API usage, resulting in service unavailability and the immediate financial exhaustion of the backend LLM service billing account.

      Affected products

      • Ecosystem: python
      • Package name: PageIndex
      • Affected versions: All versions currently in repository (main branch)
      • Patched versions:

      Severity

      • Severity: High
      • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

      Weaknesses

      • CWE: CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop')

      Occurrences

      PermalinkDescription
      pageindex/page_index.py#L303The vulnerable unbounded while loop within toc_transformer failing to cap API retry attempts.

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        No labels
        No labels

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
          Skip to content

          [Security] Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents #174

          Description

          @YLChen-007

          Advisory Details

          Title: Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents

          Description:

          Summary

          An unbounded while loop vulnerability in the toc_transformer function allows an unauthenticated attacker to cause a perpetual Denial of Service (DoS) and rapidly exhaust LLM API credits. By providing a PDF with an intentionally long Table of Contents, the system triggers length-truncated API responses that permanently trap the application into continuously querying the backend LLM API.

          Details

          The root cause resides in pageindex/page_index.py at line 303 within the toc_transformer() function. The application uses an LLM to structure a raw Table of Contents string into a hierarchical JSON format.
          If the LLM's response hits the maximum output token limit (finish_reason == "length"), the application automatically attempts to instruct the model to "continue". Crucially, the while loop lacks any retry counter or iteration limits (unlike the correctly-patched extract_toc_content function which explicitly caps attempts to 5).

          Consequently, if the model repeatedly truncates the JSON or rejects the completeness check, the execution falls into an inescapable infinite loop:

          whilenot (if_complete=="yes"andfinish_reason=="finished"):
          # ... rebuilds prompt and calls ChatGPT_API_with_finish_reasonnew_complete, finish_reason=ChatGPT_API_with_finish_reason(model=model, prompt=prompt)
          # ...if_complete=check_if_toc_transformation_is_complete(toc_content, last_complete, model)
          # NO ITERATION LIMIT OR BAILOUT CONDITION

          PoC

          1. Generate an adversarial PDF with thousands of sections in the TOC (sufficiently large to cause the LLM to truncate output), or set up a Mock OpenAI proxy that forcibly returns finish_reason: "length".
          2. Run the application via the CLI against the malicious PDF:
            python run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
          3. Observe the process forever attempting to complete the TOC, utilizing 100% of a CPU thread and rapidly emitting requests. (In a real production environment, this drastically drains OpenAI API credits).

          Log of Evidence

          [*] Setting up Mock API environment variables on port 18080
          [*] Triggering PageIndex parsing on the malicious PDF...
          [*] Executing: python3 run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
          [Target] Parsing PDF...
          [MockAPI] Returning finish_reason: 'length' (max_output_reached)
          [MockAPI] Returning completed: 'no'
          [MockAPI] Returning finish_reason: 'length' (max_output_reached)
          [MockAPI] Returning completed: 'no'
          [MockAPI] Returning finish_reason: 'length' (max_output_reached)
          [MockAPI] Returning completed: 'no'
          ...
          [!] The process has been running for over 15 seconds, stuck in the infinite loop.
          

          Impact

          This vulnerability allows a complete and unauthenticated Denial of Service (DoS) by causing process hanging and unbounded API usage, resulting in service unavailability and the immediate financial exhaustion of the backend LLM service billing account.

          Affected products

          • Ecosystem: python
          • Package name: PageIndex
          • Affected versions: All versions currently in repository (main branch)
          • Patched versions:

          Severity

          • Severity: High
          • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

          Weaknesses

          • CWE: CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop')

          Occurrences

          PermalinkDescription
          pageindex/page_index.py#L303The vulnerable unbounded while loop within toc_transformer failing to cap API retry attempts.

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            No labels
            No labels

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
              Skip to content

              [Security] Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents #174

              Description

              @YLChen-007

              Advisory Details

              Title: Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents

              Description:

              Summary

              An unbounded while loop vulnerability in the toc_transformer function allows an unauthenticated attacker to cause a perpetual Denial of Service (DoS) and rapidly exhaust LLM API credits. By providing a PDF with an intentionally long Table of Contents, the system triggers length-truncated API responses that permanently trap the application into continuously querying the backend LLM API.

              Details

              The root cause resides in pageindex/page_index.py at line 303 within the toc_transformer() function. The application uses an LLM to structure a raw Table of Contents string into a hierarchical JSON format.
              If the LLM's response hits the maximum output token limit (finish_reason == "length"), the application automatically attempts to instruct the model to "continue". Crucially, the while loop lacks any retry counter or iteration limits (unlike the correctly-patched extract_toc_content function which explicitly caps attempts to 5).

              Consequently, if the model repeatedly truncates the JSON or rejects the completeness check, the execution falls into an inescapable infinite loop:

              whilenot (if_complete=="yes"andfinish_reason=="finished"):
              # ... rebuilds prompt and calls ChatGPT_API_with_finish_reasonnew_complete, finish_reason=ChatGPT_API_with_finish_reason(model=model, prompt=prompt)
              # ...if_complete=check_if_toc_transformation_is_complete(toc_content, last_complete, model)
              # NO ITERATION LIMIT OR BAILOUT CONDITION

              PoC

              1. Generate an adversarial PDF with thousands of sections in the TOC (sufficiently large to cause the LLM to truncate output), or set up a Mock OpenAI proxy that forcibly returns finish_reason: "length".
              2. Run the application via the CLI against the malicious PDF:
                python run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
              3. Observe the process forever attempting to complete the TOC, utilizing 100% of a CPU thread and rapidly emitting requests. (In a real production environment, this drastically drains OpenAI API credits).

              Log of Evidence

              [*] Setting up Mock API environment variables on port 18080
              [*] Triggering PageIndex parsing on the malicious PDF...
              [*] Executing: python3 run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
              [Target] Parsing PDF...
              [MockAPI] Returning finish_reason: 'length' (max_output_reached)
              [MockAPI] Returning completed: 'no'
              [MockAPI] Returning finish_reason: 'length' (max_output_reached)
              [MockAPI] Returning completed: 'no'
              [MockAPI] Returning finish_reason: 'length' (max_output_reached)
              [MockAPI] Returning completed: 'no'
              ...
              [!] The process has been running for over 15 seconds, stuck in the infinite loop.
              

              Impact

              This vulnerability allows a complete and unauthenticated Denial of Service (DoS) by causing process hanging and unbounded API usage, resulting in service unavailability and the immediate financial exhaustion of the backend LLM service billing account.

              Affected products

              • Ecosystem: python
              • Package name: PageIndex
              • Affected versions: All versions currently in repository (main branch)
              • Patched versions:

              Severity

              • Severity: High
              • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

              Weaknesses

              • CWE: CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop')

              Occurrences

              PermalinkDescription
              pageindex/page_index.py#L303The vulnerable unbounded while loop within toc_transformer failing to cap API retry attempts.

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                No labels
                No labels

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
                  Skip to content

                  [Security] Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents #174

                  Description

                  @YLChen-007

                  Advisory Details

                  Title: Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents

                  Description:

                  Summary

                  An unbounded while loop vulnerability in the toc_transformer function allows an unauthenticated attacker to cause a perpetual Denial of Service (DoS) and rapidly exhaust LLM API credits. By providing a PDF with an intentionally long Table of Contents, the system triggers length-truncated API responses that permanently trap the application into continuously querying the backend LLM API.

                  Details

                  The root cause resides in pageindex/page_index.py at line 303 within the toc_transformer() function. The application uses an LLM to structure a raw Table of Contents string into a hierarchical JSON format.
                  If the LLM's response hits the maximum output token limit (finish_reason == "length"), the application automatically attempts to instruct the model to "continue". Crucially, the while loop lacks any retry counter or iteration limits (unlike the correctly-patched extract_toc_content function which explicitly caps attempts to 5).

                  Consequently, if the model repeatedly truncates the JSON or rejects the completeness check, the execution falls into an inescapable infinite loop:

                  whilenot (if_complete=="yes"andfinish_reason=="finished"):
                  # ... rebuilds prompt and calls ChatGPT_API_with_finish_reasonnew_complete, finish_reason=ChatGPT_API_with_finish_reason(model=model, prompt=prompt)
                  # ...if_complete=check_if_toc_transformation_is_complete(toc_content, last_complete, model)
                  # NO ITERATION LIMIT OR BAILOUT CONDITION

                  PoC

                  1. Generate an adversarial PDF with thousands of sections in the TOC (sufficiently large to cause the LLM to truncate output), or set up a Mock OpenAI proxy that forcibly returns finish_reason: "length".
                  2. Run the application via the CLI against the malicious PDF:
                    python run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
                  3. Observe the process forever attempting to complete the TOC, utilizing 100% of a CPU thread and rapidly emitting requests. (In a real production environment, this drastically drains OpenAI API credits).

                  Log of Evidence

                  [*] Setting up Mock API environment variables on port 18080
                  [*] Triggering PageIndex parsing on the malicious PDF...
                  [*] Executing: python3 run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
                  [Target] Parsing PDF...
                  [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                  [MockAPI] Returning completed: 'no'
                  [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                  [MockAPI] Returning completed: 'no'
                  [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                  [MockAPI] Returning completed: 'no'
                  ...
                  [!] The process has been running for over 15 seconds, stuck in the infinite loop.
                  

                  Impact

                  This vulnerability allows a complete and unauthenticated Denial of Service (DoS) by causing process hanging and unbounded API usage, resulting in service unavailability and the immediate financial exhaustion of the backend LLM service billing account.

                  Affected products

                  • Ecosystem: python
                  • Package name: PageIndex
                  • Affected versions: All versions currently in repository (main branch)
                  • Patched versions:

                  Severity

                  • Severity: High
                  • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

                  Weaknesses

                  • CWE: CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop')

                  Occurrences

                  PermalinkDescription
                  pageindex/page_index.py#L303The vulnerable unbounded while loop within toc_transformer failing to cap API retry attempts.

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Labels

                    No labels
                    No labels

                    Type

                    No type

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                      Skip to content

                      [Security] Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents #174

                      Description

                      @YLChen-007

                      Advisory Details

                      Title: Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents

                      Description:

                      Summary

                      An unbounded while loop vulnerability in the toc_transformer function allows an unauthenticated attacker to cause a perpetual Denial of Service (DoS) and rapidly exhaust LLM API credits. By providing a PDF with an intentionally long Table of Contents, the system triggers length-truncated API responses that permanently trap the application into continuously querying the backend LLM API.

                      Details

                      The root cause resides in pageindex/page_index.py at line 303 within the toc_transformer() function. The application uses an LLM to structure a raw Table of Contents string into a hierarchical JSON format.
                      If the LLM's response hits the maximum output token limit (finish_reason == "length"), the application automatically attempts to instruct the model to "continue". Crucially, the while loop lacks any retry counter or iteration limits (unlike the correctly-patched extract_toc_content function which explicitly caps attempts to 5).

                      Consequently, if the model repeatedly truncates the JSON or rejects the completeness check, the execution falls into an inescapable infinite loop:

                      whilenot (if_complete=="yes"andfinish_reason=="finished"):
                      # ... rebuilds prompt and calls ChatGPT_API_with_finish_reasonnew_complete, finish_reason=ChatGPT_API_with_finish_reason(model=model, prompt=prompt)
                      # ...if_complete=check_if_toc_transformation_is_complete(toc_content, last_complete, model)
                      # NO ITERATION LIMIT OR BAILOUT CONDITION

                      PoC

                      1. Generate an adversarial PDF with thousands of sections in the TOC (sufficiently large to cause the LLM to truncate output), or set up a Mock OpenAI proxy that forcibly returns finish_reason: "length".
                      2. Run the application via the CLI against the malicious PDF:
                        python run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
                      3. Observe the process forever attempting to complete the TOC, utilizing 100% of a CPU thread and rapidly emitting requests. (In a real production environment, this drastically drains OpenAI API credits).

                      Log of Evidence

                      [*] Setting up Mock API environment variables on port 18080
                      [*] Triggering PageIndex parsing on the malicious PDF...
                      [*] Executing: python3 run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
                      [Target] Parsing PDF...
                      [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                      [MockAPI] Returning completed: 'no'
                      [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                      [MockAPI] Returning completed: 'no'
                      [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                      [MockAPI] Returning completed: 'no'
                      ...
                      [!] The process has been running for over 15 seconds, stuck in the infinite loop.
                      

                      Impact

                      This vulnerability allows a complete and unauthenticated Denial of Service (DoS) by causing process hanging and unbounded API usage, resulting in service unavailability and the immediate financial exhaustion of the backend LLM service billing account.

                      Affected products

                      • Ecosystem: python
                      • Package name: PageIndex
                      • Affected versions: All versions currently in repository (main branch)
                      • Patched versions:

                      Severity

                      • Severity: High
                      • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

                      Weaknesses

                      • CWE: CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop')

                      Occurrences

                      PermalinkDescription
                      pageindex/page_index.py#L303The vulnerable unbounded while loop within toc_transformer failing to cap API retry attempts.

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Labels

                        No labels
                        No labels

                        Type

                        No type

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                          Skip to content

                          [Security] Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents #174

                          Description

                          @YLChen-007

                          Advisory Details

                          Title: Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents

                          Description:

                          Summary

                          An unbounded while loop vulnerability in the toc_transformer function allows an unauthenticated attacker to cause a perpetual Denial of Service (DoS) and rapidly exhaust LLM API credits. By providing a PDF with an intentionally long Table of Contents, the system triggers length-truncated API responses that permanently trap the application into continuously querying the backend LLM API.

                          Details

                          The root cause resides in pageindex/page_index.py at line 303 within the toc_transformer() function. The application uses an LLM to structure a raw Table of Contents string into a hierarchical JSON format.
                          If the LLM's response hits the maximum output token limit (finish_reason == "length"), the application automatically attempts to instruct the model to "continue". Crucially, the while loop lacks any retry counter or iteration limits (unlike the correctly-patched extract_toc_content function which explicitly caps attempts to 5).

                          Consequently, if the model repeatedly truncates the JSON or rejects the completeness check, the execution falls into an inescapable infinite loop:

                          whilenot (if_complete=="yes"andfinish_reason=="finished"):
                          # ... rebuilds prompt and calls ChatGPT_API_with_finish_reasonnew_complete, finish_reason=ChatGPT_API_with_finish_reason(model=model, prompt=prompt)
                          # ...if_complete=check_if_toc_transformation_is_complete(toc_content, last_complete, model)
                          # NO ITERATION LIMIT OR BAILOUT CONDITION

                          PoC

                          1. Generate an adversarial PDF with thousands of sections in the TOC (sufficiently large to cause the LLM to truncate output), or set up a Mock OpenAI proxy that forcibly returns finish_reason: "length".
                          2. Run the application via the CLI against the malicious PDF:
                            python run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
                          3. Observe the process forever attempting to complete the TOC, utilizing 100% of a CPU thread and rapidly emitting requests. (In a real production environment, this drastically drains OpenAI API credits).

                          Log of Evidence

                          [*] Setting up Mock API environment variables on port 18080
                          [*] Triggering PageIndex parsing on the malicious PDF...
                          [*] Executing: python3 run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
                          [Target] Parsing PDF...
                          [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                          [MockAPI] Returning completed: 'no'
                          [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                          [MockAPI] Returning completed: 'no'
                          [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                          [MockAPI] Returning completed: 'no'
                          ...
                          [!] The process has been running for over 15 seconds, stuck in the infinite loop.
                          

                          Impact

                          This vulnerability allows a complete and unauthenticated Denial of Service (DoS) by causing process hanging and unbounded API usage, resulting in service unavailability and the immediate financial exhaustion of the backend LLM service billing account.

                          Affected products

                          • Ecosystem: python
                          • Package name: PageIndex
                          • Affected versions: All versions currently in repository (main branch)
                          • Patched versions:

                          Severity

                          • Severity: High
                          • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

                          Weaknesses

                          • CWE: CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop')

                          Occurrences

                          PermalinkDescription
                          pageindex/page_index.py#L303The vulnerable unbounded while loop within toc_transformer failing to cap API retry attempts.

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Labels

                            No labels
                            No labels

                            Type

                            No type

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
                              Skip to content

                              [Security] Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents #174

                              Description

                              @YLChen-007

                              Advisory Details

                              Title: Arbitrary Infinite Loop Denial of Service (DoS) via Crafted PDF Table of Contents

                              Description:

                              Summary

                              An unbounded while loop vulnerability in the toc_transformer function allows an unauthenticated attacker to cause a perpetual Denial of Service (DoS) and rapidly exhaust LLM API credits. By providing a PDF with an intentionally long Table of Contents, the system triggers length-truncated API responses that permanently trap the application into continuously querying the backend LLM API.

                              Details

                              The root cause resides in pageindex/page_index.py at line 303 within the toc_transformer() function. The application uses an LLM to structure a raw Table of Contents string into a hierarchical JSON format.
                              If the LLM's response hits the maximum output token limit (finish_reason == "length"), the application automatically attempts to instruct the model to "continue". Crucially, the while loop lacks any retry counter or iteration limits (unlike the correctly-patched extract_toc_content function which explicitly caps attempts to 5).

                              Consequently, if the model repeatedly truncates the JSON or rejects the completeness check, the execution falls into an inescapable infinite loop:

                              whilenot (if_complete=="yes"andfinish_reason=="finished"):
                              # ... rebuilds prompt and calls ChatGPT_API_with_finish_reasonnew_complete, finish_reason=ChatGPT_API_with_finish_reason(model=model, prompt=prompt)
                              # ...if_complete=check_if_toc_transformation_is_complete(toc_content, last_complete, model)
                              # NO ITERATION LIMIT OR BAILOUT CONDITION

                              PoC

                              1. Generate an adversarial PDF with thousands of sections in the TOC (sufficiently large to cause the LLM to truncate output), or set up a Mock OpenAI proxy that forcibly returns finish_reason: "length".
                              2. Run the application via the CLI against the malicious PDF:
                                python run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
                              3. Observe the process forever attempting to complete the TOC, utilizing 100% of a CPU thread and rapidly emitting requests. (In a real production environment, this drastically drains OpenAI API credits).

                              Log of Evidence

                              [*] Setting up Mock API environment variables on port 18080
                              [*] Triggering PageIndex parsing on the malicious PDF...
                              [*] Executing: python3 run_pageindex.py --pdf_path evil_toc.pdf --model gpt-3.5-turbo
                              [Target] Parsing PDF...
                              [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                              [MockAPI] Returning completed: 'no'
                              [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                              [MockAPI] Returning completed: 'no'
                              [MockAPI] Returning finish_reason: 'length' (max_output_reached)
                              [MockAPI] Returning completed: 'no'
                              ...
                              [!] The process has been running for over 15 seconds, stuck in the infinite loop.
                              

                              Impact

                              This vulnerability allows a complete and unauthenticated Denial of Service (DoS) by causing process hanging and unbounded API usage, resulting in service unavailability and the immediate financial exhaustion of the backend LLM service billing account.

                              Affected products

                              • Ecosystem: python
                              • Package name: PageIndex
                              • Affected versions: All versions currently in repository (main branch)
                              • Patched versions:

                              Severity

                              • Severity: High
                              • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

                              Weaknesses

                              • CWE: CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop')

                              Occurrences

                              PermalinkDescription
                              pageindex/page_index.py#L303The vulnerable unbounded while loop within toc_transformer failing to cap API retry attempts.

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Labels

                                No labels
                                No labels

                                Type

                                No type

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions