{"id":"CVE-2026-82868","aliases":["GHSA-87v3-4cfp-cm76"],"url":"https://o3.security/vulnerability/CVE-2026-82868","summary":"@pdfme/schemas before 5.5.9 Cross-Site Scripting via SVG","details":"## Summary\n\nThe SVG schema plugin in `@pdfme/schemas` renders user-supplied SVG content using `container.innerHTML = value` without any sanitization, enabling arbitrary JavaScript execution in the user's browser.\n\n## Details\n\nIn `packages/schemas/src/graphics/svg.ts`, line 87, the SVG schema's `ui` renderer assigns raw SVG markup directly to `innerHTML` when in viewer mode or form mode with `readOnly: true`:\n\n```typescript\n// svg.ts, line 81-94 (non-editable rendering path)\n} else {\n  if (!value) return;\n  if (!isValidSVG(value)) {\n    rootElement.appendChild(createErrorElm());\n    return;\n  }\n  container.innerHTML = value;  // <-- VULNERABLE: unsanitized SVG injected into DOM\n  const svgElement = container.childNodes[0];\n  if (svgElement instanceof SVGElement) {\n    svgElement.setAttribute('width', '100%');\n    svgElement.setAttribute('height', '100%');\n    rootElement.appendChild(container);\n  }\n}\n```\n\nThe `isValidSVG()` function (lines 11-37) only validates that the string contains `<svg` and `</svg>` tags and passes `DOMParser` well-formedness checks. It does NOT strip or block:\n- `<script>` tags embedded in SVG\n- Event handler attributes (`onload`, `onerror`, `onclick`, etc.)\n- `<foreignObject>` elements containing HTML with event handlers\n- `<animate>` / `<set>` elements with `onbegin` / `onend` handlers\n- SVG `<use>` elements referencing malicious external resources\n\nAll of these are valid SVG and pass `isValidSVG()`, but execute JavaScript when inserted via `innerHTML`.\n\n## Attack Vectors\n\n### 1. Malicious Template (readOnly SVG schema)\nAn attacker crafts a template JSON with a readOnly SVG schema containing a malicious `content` value. When loaded into the pdfme Form or Viewer component, the SVG executes JavaScript.\n\n### 2. Application-Supplied Inputs + Viewer\nIf an application uses the pdfme Viewer component and passes user-controlled data as inputs for a non-readOnly SVG schema, the attacker's SVG flows directly to `innerHTML`.\n\n## Proof of Concept\n\nLoading the following template into a pdfme Form or Viewer component triggers JavaScript execution:\n\n```json\n{\n  \"basePdf\": { \"width\": 210, \"height\": 297, \"padding\": [20, 20, 20, 20] },\n  \"schemas\": [[\n    {\n      \"name\": \"malicious_svg\",\n      \"type\": \"svg\",\n      \"content\": \"<svg xmlns='http://www.w3.org/2000/svg' onload='alert(document.domain)'><rect width='100' height='100' fill='red'/></svg>\",\n      \"readOnly\": true,\n      \"position\": { \"x\": 20, \"y\": 20 },\n      \"width\": 80,\n      \"height\": 40\n    }\n  ]]\n}\n```\n\nAdditional payloads that bypass `isValidSVG()` and execute JavaScript:\n\n```svg\n<!-- Via foreignObject -->\n<svg xmlns=\"http://www.w3.org/2000/svg\"><foreignObject width=\"200\" height=\"60\"><body xmlns=\"http://www.w3.org/1999/xhtml\"><img src=\"x\" onerror=\"alert(1)\"/></body></foreignObject></svg>\n\n<!-- Via animate onbegin -->\n<svg xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"100\" height=\"100\"><animate attributeName=\"x\" values=\"0\" dur=\"0.001s\" onbegin=\"alert(1)\"/></rect></svg>\n```\n\n## Impact\n\nAn attacker who can supply a malicious template (via file upload, shared template URL, multi-tenant template storage, or `updateTemplate()` API) can execute arbitrary JavaScript in the context of any user who views or fills the template. This enables:\n- Session hijacking via cookie/token theft\n- Keylogging of form inputs (including sensitive data being entered into PDF forms)\n- Phishing attacks by modifying the rendered page\n- Data exfiltration from the application\n\nThe attack is particularly concerning for multi-tenant SaaS applications using pdfme where templates may be user-supplied.\n\n## Suggested Fix\n\nSanitize SVG content before DOM insertion using DOMPurify or a similar library:\n\n```typescript\nimport DOMPurify from 'dompurify';\n\n// Replace line 87:\ncontainer.innerHTML = DOMPurify.sanitize(value, { USE_PROFILES: { svg: true } });\n```\n\nAlternatively, parse the SVG via `DOMParser`, strip all script elements and event handler attributes, then append the sanitized DOM nodes.","published":"2026-08-31T08:46:38.149Z","modified":"2026-10-28T02:30:30.551008344Z","cvss":null,"epss":null,"cisaKev":null,"exploitsKnown":null,"affectedPackages":[{"ecosystem":"npm","name":"@pdfme/schemas","fixedVersion":"5.5.9"}],"fix":null,"references":[{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/82xxx/CVE-2026-82868.json"},{"type":"ADVISORY","url":"https://github.com/pdfme/pdfme/security/advisories/GHSA-87v3-4cfp-cm76"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-82868"},{"type":"ADVISORY","url":"https://www.vulncheck.com/advisories/pdfme-schemas-before-5.5.9-cross-site-scripting-via-svg"},{"type":"PACKAGE","url":"https://github.com/pdfme/pdfme"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-10-28T02:30:30.551008344Z"}}