Summary
The 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.
Details
In 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:
// svg.ts, line 81-94 (non-editable rendering path)
} else {
if (!value) return;
if (!isValidSVG(value)) {
rootElement.appendChild(createErrorElm());
return;
}
container.innerHTML = value; // <-- VULNERABLE: unsanitized SVG injected into DOM
const svgElement = container.childNodes[0];
if (svgElement instanceof SVGElement) {
svgElement.setAttribute('width', '100%');
svgElement.setAttribute('height', '100%');
rootElement.appendChild(container);
}
}
The 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:
<script>tags embedded in SVG- Event handler attributes (
onload,onerror,onclick, etc.) <foreignObject>elements containing HTML with event handlers<animate>/<set>elements withonbegin/onendhandlers- SVG
<use>elements referencing malicious external resources
All of these are valid SVG and pass isValidSVG(), but execute JavaScript when inserted via innerHTML.
Attack Vectors
1. Malicious Template (readOnly SVG schema)
An 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.
2. Application-Supplied Inputs + Viewer
If 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.
Proof of Concept
Loading the following template into a pdfme Form or Viewer component triggers JavaScript execution:
{
"basePdf": { "width": 210, "height": 297, "padding": [20, 20, 20, 20] },
"schemas": [[
{
"name": "malicious_svg",
"type": "svg",
"content": "<svg xmlns='http://www.w3.org/2000/svg' onload='alert(document.domain)'><rect width='100' height='100' fill='red'/></svg>",
"readOnly": true,
"position": { "x": 20, "y": 20 },
"width": 80,
"height": 40
}
]]
}
Additional payloads that bypass isValidSVG() and execute JavaScript:
<!-- Via foreignObject -->
<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>
<!-- Via animate onbegin -->
<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>
Impact
An 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:
- Session hijacking via cookie/token theft
- Keylogging of form inputs (including sensitive data being entered into PDF forms)
- Phishing attacks by modifying the rendered page
- Data exfiltration from the application
The attack is particularly concerning for multi-tenant SaaS applications using pdfme where templates may be user-supplied.
Untrusted input is rendered as active markup in a victim's browser, which can run script in their session. Typical impact: session or credential theft, and actions taken as the user.
GHSA-87V3-4CFP-CM76 has a CVSS score of 6.1 (Medium). The vector is network-reachable, no privileges required, and user interaction required. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (5.5.9); upgrading removes the vulnerable code path.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Remediation advice
Sanitize SVG content before DOM insertion using DOMPurify or a similar library:
import DOMPurify from 'dompurify';
// Replace line 87:
container.innerHTML = DOMPurify.sanitize(value, { USE_PROFILES: { svg: true } });
Alternatively, parse the SVG via DOMParser, strip all script elements and event handler attributes, then append the sanitized DOM nodes.
Frequently Asked Questions
- What is GHSA-87V3-4CFP-CM76? GHSA-87V3-4CFP-CM76 is a medium-severity cross-site scripting (XSS) vulnerability in @pdfme/schemas (npm), affecting versions <= 5.5.8. It is fixed in 5.5.9. Untrusted input is rendered as active markup in a victim's browser, which can run script in their session.
- How severe is GHSA-87V3-4CFP-CM76? GHSA-87V3-4CFP-CM76 has a CVSS score of 6.1 (Medium). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of @pdfme/schemas are affected by GHSA-87V3-4CFP-CM76? @pdfme/schemas (npm) versions <= 5.5.8 is affected.
- Is there a fix for GHSA-87V3-4CFP-CM76? Yes. GHSA-87V3-4CFP-CM76 is fixed in 5.5.9. Upgrade to this version or later.
- Is GHSA-87V3-4CFP-CM76 exploitable, and should I be worried? Whether GHSA-87V3-4CFP-CM76 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether GHSA-87V3-4CFP-CM76 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix GHSA-87V3-4CFP-CM76? Upgrade
@pdfme/schemasto 5.5.9 or later.