github dichovsky/pdf-to-png-converter v3.15.0
v3.15.0 — Security hardening & input widening

5 hours ago

What's new

Security fixes

Four vulnerabilities identified and patched in this release:

Critical — DoS via infinite loop (concurrencyLimit)
Passing concurrencyLimit: 0 or any negative integer with processPagesInParallel: true caused an infinite loop that permanently blocked the event loop. concurrencyLimit is now validated as a positive integer (>= 1) before any I/O; invalid values throw immediately.

High — Out-of-memory via unbounded viewportScale
viewportScale had no upper bound. A value of 1e6 produced a canvas allocation of ~200 TB, crashing the process with ENOMEM. Two guards were added:

  • viewportScale is now capped at 1000 (validated before the first await)
  • A canvas pixel-area cap of 100,000,000 px (≈ 400 MB at 4 bytes/px) is enforced per page before any allocation

Medium — TOCTOU race in write-containment guard
A symlink swap between the realpath() containment check and writeFile() could redirect output to an arbitrary path. A second realpath() re-verification is now performed immediately before writeFile(), narrowing the race window to its minimum. The residual limitation (inherent to userspace POSIX I/O) is documented in JSDoc and PdfToPngOptions.

Low — Path traversal via outputFileMaskFunc
A custom outputFileMaskFunc returning ../secret.png or an absolute path could write outside the declared outputFolder. A segment-aware containment check using path.relative() + realpath() now rejects any filename that escapes the output directory.


New feature — Uint8Array and Buffer accepted as direct input

The pdfFile parameter type is widened from string | ArrayBufferLike to string | ArrayBufferLike | Uint8Array. Node.js Buffer instances are also accepted directly without wrapping. Internal buffer normalisation avoids the double-copy that previously occurred for ArrayBufferLike inputs.

// All of these now work:
await pdfToPng(fs.readFileSync('doc.pdf'));           // Buffer
await pdfToPng(new Uint8Array(rawBytes));             // Uint8Array
await pdfToPng(arrayBuffer);                          // ArrayBuffer (unchanged)
await pdfToPng('/path/to/doc.pdf');                   // string (unchanged)

Package improvements

  • Added "type": "commonjs" for explicit module format declaration
  • Added "require" condition to the exports field for better CJS tooling compatibility
  • Removed dead build:docker script and predocker:test lifecycle hook
  • Updated package description to accurately reflect pre-built native binaries
  • Corrected .dockerignore to exclude .env, .claude/, and other local-only files from the Docker build context

Breaking changes

These changes throw in cases that previously caused silent wrong behavior:

Option Old behavior New behavior
viewportScale > 1000 Process crash (OOM) Throws Error immediately
viewportScale <= 0 or non-finite Throws (unchanged) Throws (unchanged)
concurrencyLimit < 1 with processPagesInParallel: true Infinite loop / hang Throws Error immediately
Canvas > 100,000,000 px Process crash (OOM) Throws Error per page
outputFileMaskFunc returning ../ path Writes outside outputFolder Throws Error

Upgrade guide

No API changes are required for standard usage. If your code explicitly relies on any of the behaviors listed in the breaking changes table above, update accordingly:

  • Keep viewportScale in the range (0, 1000] — values above 12× are rarely useful in practice (600 dpi A0 paper ≈ scale 12)
  • Keep concurrencyLimit as a positive integer (>= 1) when processPagesInParallel: true

Don't miss a new pdf-to-png-converter release

NewReleases is sending notifications on new releases.