# REPRO-2026-00044: jsPDF Local File Inclusion/Path Traversal in Node.js builds ## Summary Status: published Severity: critical Type: security Confidence: Unknown ## Identifiers REPRO ID: REPRO-2026-00044 GHSA: GHSA-f8cm-6447-x5h2 CVE: CVE-2025-68428 ## Package Name: jspdf Ecosystem: npm Affected: <= 3.0.4 Fixed: 4.0.0 ## Root Cause # Root Cause Analysis - GHSA-f8cm-6447-x5h2 (jsPDF Local File Inclusion / Path Traversal) Summary - Vulnerability: Local File Inclusion/Path Traversal via file-loading helpers in jsPDF Node builds - Impact: Attacker-controlled path arguments to jsPDF APIs can read arbitrary files on the server and embed their raw bytes into generated PDFs - Affected: jsPDF <= 3.0.4 (Node builds: dist/jspdf.node.js and dist/jspdf.node.min.js) - Fixed: jsPDF >= 4.0.0 (default deny FS reads; requires explicit enable or Node --permission) Reproduction Evidence - Vulnerable version 3.0.4: Passing a local path to doc.addImage(secret.txt, ...) produced a PDF containing the secret token from a local file - See logs: logs/run_*.log -> shows [HIT] for vulnerable:addImage - Artifact: repro_work/vuln/out_addImage.pdf contains the token string (search via `grep -a`) - Patched version 4.0.0 (latest at test time): Same PoC raises an error and does not create a PDF - Error: "Trying to read a file from local file system... set jsPDF.allowFsRead or use --permission --allow-fs-read" - No token present in patched outputs; bypass suite attempts did not exfiltrate Root Cause Details - In Node builds <=3.0.4, helper function loadFile() directly accepted user-provided paths and read files without restriction. Several high-level APIs (addImage, html, addFont) used this helper when passed a string path (as opposed to binary data), causing raw file contents to be embedded in the PDF stream. - The 4.0.0 patch introduces permission gating for file system access with jsPDF.allowFsRead defaulting to false and honoring Node.js permission model flags. Calls trying to resolve string paths emit a hard error unless enabled. Exploitation Path 1. Import jsPDF Node build (require('jspdf/dist/jspdf.node.js')) 2. Provide attacker-controlled relative or absolute path to doc.addImage (or html/addFont) 3. Vulnerable loader reads the file and embeds content verbatim into the PDF 4. Attacker obtains the PDF and extracts embedded sensitive content Patched Behavior Verification - Tested latest npm release (4.0.0) which is newer than the first patched tag or equal; verified it blocks file reads by default - Error message confirms new permission gate; no PDFs contained secret token Mitigations/Recommendations - Upgrade to jsPDF >= 4.0.0 - In production Node 22+/23+/24+, use --permission with --allow-fs-read narrowly scoped if jsPDF needs local asset reads - For older Node versions, sanitize and whitelist any paths passed to jsPDF APIs; avoid passing user-provided paths directly Artifacts - logs/run_*.log: Full run logs including errors and hits/misses - logs/summary.log: Reproduction summary (FOUND/MISSING etc.) - repro_work/vuln/out_addImage.pdf: Vulnerable PoC artifact containing secret token - repro_work/patched/*: Patched tests and bypass attempts outputs ## Reproduction Details Reproduced: 2026-01-07T19:54:33.503Z Duration: 494 seconds Tool calls: 34 Turns: 2 Handoffs: 1 ## Timeline (Key Moments) 1. [poc_created] Repro Script Created (repro) The reproduction script was written to automate the exploit steps. 2. [env_setup] Repro Script Executed (repro) The vulnerable environment was set up and the reproduction script was run. 3. [vuln_triggered] Exploit Attempted (repro) The exploit was executed again to trigger the vulnerability. 4. [discovery] Secret Token Located (repro) A critical secret token related to the vulnerability was found in the logs. 5. [confirmation] Repro Validated (repro) A fully self-contained reproduction was created and validated successfully. ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00044 pruva-verify GHSA-f8cm-6447-x5h2 pruva-verify CVE-2025-68428 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00044&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00044/artifacts/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - GitHub Advisory: https://github.com/advisories/GHSA-f8cm-6447-x5h2 - NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-68428 - Source: https://nvd.nist.gov/vuln/detail/CVE-2025-68428 ## Artifacts - repro/rca_report.md (analysis, 2860 bytes) - reproduction_steps.sh (reproduction_script, 11524 bytes) - logs/run_20260107_182602.log (log, 26460 bytes) - logs/run_20260107_182758.log (log, 27579 bytes) - logs/run_20260107_182811.log (log, 27579 bytes) - logs/summary.log (log, 112 bytes) - repro/patch_analysis.md (documentation, 3167 bytes) - repro/repro_notes.txt (other, 500 bytes) - repro_work/patched/attempts/5_addFont_rel.pdf (other, 3318 bytes) - repro_work/patched/attempts/6_addFont_abs.pdf (other, 3387 bytes) - repro_work/patched/package.json (other, 50 bytes) - repro_work/patched/patch_attempt_1.js (other, 1946 bytes) - repro_work/patched/patch_attempt_10.js (other, 1946 bytes) - repro_work/patched/patch_attempt_11.js (other, 1946 bytes) - repro_work/patched/patch_attempt_2.js (other, 1946 bytes) - repro_work/patched/patch_attempt_3.js (other, 1946 bytes) - repro_work/patched/patch_attempt_4.js (other, 1946 bytes) - repro_work/patched/patch_attempt_5.js (other, 1946 bytes) - repro_work/patched/patch_attempt_6.js (other, 1946 bytes) - repro_work/patched/patch_attempt_7.js (other, 1946 bytes) - repro_work/patched/patch_attempt_8.js (other, 1946 bytes) - repro_work/patched/patch_attempt_9.js (other, 1946 bytes) - repro_work/patched/poc_addimage.js (other, 718 bytes) - repro_work/vuln/out_addFont.pdf (other, 3397 bytes) - repro_work/vuln/out_addImage.pdf (other, 3473 bytes) - repro_work/vuln/package.json (other, 50 bytes) - repro_work/vuln/poc_addfont.js (other, 674 bytes) - repro_work/vuln/poc_addimage.js (other, 718 bytes) - secret.txt (other, 119 bytes) - ticket.md (ticket, 2032 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00044 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00044/artifacts/reproduction_steps.sh - Web: https://pruva.dev/r/REPRO-2026-00044 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev