Print to Pwned: The DOM XSS Inside html2pdf.js
Vulnerability ID: CVE-2026-22787
CVSS Score: 8.7
Published: 2026-01-14
A high-severity Cross-Site Scripting (XSS) vulnerability in the popular html2pdf.js library allows attackers to execute arbitrary JavaScript by injecting malicious HTML strings during PDF generation.
TL;DR
The html2pdf.js library (versions < 0.14.0) attempted to sanitize HTML input by manually removing tags <em>after</em> adding them to the DOM. This 'blacklist' approach failed spectacularly because inline event handlers (like onerror) execute immediately upon parsing. The fix involves implementing DOMPurify to whitelist safe HTML before it ever touches the document.</p> <hr> <h3> <a name="exploit-status-poc" href="#exploit-status-poc" class="anchor"> </a> ⚠️ Exploit Status: POC </h3> <h2> <a name="technical-details" href="#technical-details" class="anchor"> </a> Technical Details </h2> <ul> <li><strong>CWE ID</strong>: CWE-79 (Improper Neutralization of Input During Web Page Generation)</li> <li><strong>Attack Vector</strong>: Network (Client-Side)</li> <li><strong>CVSS v4.0</strong>: 8.7 (High)</li> <li><strong>Impact</strong>: High Confidentiality, High Integrity</li> <li><strong>Exploit Status</strong>: PoC Available / Trivial</li> <li><strong>Affected Component</strong>: src/utils.js:createElement</li> </ul> <h2> <a name="affected-systems" href="#affected-systems" class="anchor"> </a> Affected Systems </h2> <ul> <li>Web applications using html2pdf.js < 0.14.0</li> <li>Single Page Applications (SPAs) generating client-side reports</li> <li>Invoice generators</li> <li>Ticket/Receipt printing services</li> <li><strong>html2pdf.js</strong>: < 0.14.0 (Fixed in: <code>0.14.0</code>)</li> </ul> <h2> <a name="code-analysis" href="#code-analysis" class="anchor"> </a> Code Analysis </h2> <h3> <a name="commit-988826e" href="#commit-988826e" class="anchor"> </a> Commit: <a href="https://github.com/eKoopmans/html2pdf.js/commit/988826e336035b39a8608182d7b73c0e3cd78c7b">988826e</a> </h3> <p>Fix: sanitize text source (resolve #865)<br> </p> <div class="highlight"><pre class="highlight diff"><code><span class="gd">- if (opt.innerHTML) { - el.innerHTML = opt.innerHTML; - var scripts = el.getElementsByTagName('script'); - for (var i = scripts.length; i-- > 0; null) { - scripts[i].parentNode.removeChild(scripts[i]); - } - } </span><span class="gi">+ if (opt.innerHTML) el.innerHTML = DOMPurify.sanitize(opt.innerHTML); </span></code></pre></div> <p></p> <h2> <a name="exploit-details" href="#exploit-details" class="anchor"> </a> Exploit Details </h2> <ul> <li><a href="https://github.com/eKoopmans/html2pdf.js/issues/865">GitHub Issue</a>: Original bug report demonstrating XSS via string input</li> <li><a href="https://dev.toN/A">PoC</a>: html2pdf().from('<img src=x onerror=alert(1)>').save()</li> </ul> <h2> <a name="mitigation-strategies" href="#mitigation-strategies" class="anchor"> </a> Mitigation Strategies </h2> <ul> <li>Upgrade html2pdf.js to version 0.14.0 or later immediately.</li> <li>Implement Content Security Policy (CSP) headers to restrict script execution sources.</li> <li>Sanitize user input on the server-side as a defense-in-depth measure.</li> <li>Avoid passing raw strings to the <code>.from()</code> method; pass sanitized DOM nodes instead.</li> </ul> <p><strong>Remediation Steps:</strong></p> <ol> <li>Run <code>npm install html2pdf.js@latest</code> or <code>yarn upgrade html2pdf.js</code>.</li> <li>Verify that <code>package.json</code> reflects version <code>^0.14.0</code>.</li> <li>Audit your codebase for usage of <code>html2pdf().from(variable)</code>. Ensure <code>variable</code> is not raw user input.</li> <li>Rebuild and deploy your application assets.</li> </ol> <h2> <a name="references" href="#references" class="anchor"> </a> References </h2> <ul> <li><a href="https://github.com/eKoopmans/html2pdf.js/security/advisories/GHSA-w8x4-x68c-m6fc">GHSA Advisory</a></li> <li><a href="https://github.com/eKoopmans/html2pdf.js/pull/877">Pull Request #877</a></li> </ul> <hr> <p><em><a href="https://cvereports.com/reports/CVE-2026-22787">Read the full report for CVE-2026-22787 on our website</a> for more details including interactive diagrams and full exploit analysis.</em></p>
Top comments (0)