Skip to content

Corrupt PNG throws uncatchable error #1747

Description

@robbertbrak

Bug Report

Description

When embedding a PNG which IDAT data is corrupted or truncated, pdfkit crashes the process with an uncaught exception. The error cannot be caught by the caller: wrapping inside try/catch does not work, and no error event is emitted on the document.

The root cause is in the png-js dependency. In decodePixels, it calls zlib.inflate and re-throws the error from inside the asynchronous callback:

decodePixels(fn) {
  return zlib.inflate(this.imgData, (err, data) => {
    if (err) {
      throw err;
    }
    ...

This happens specifically when pdfkit needs to access the raw pixels, for example for PNGs with transparency.

How to reproduce

Create a script as follows:

const PDFDocument = require('pdfkit');
const fs = require('fs');
const zlib = require('zlib');

// Construct a PNG which IDAT payload is not a valid zlib stream
function chunk(type, data) {
  const len = Buffer.alloc(4);
  len.writeUInt32BE(data.length);
  const body = Buffer.concat([Buffer.from(type, 'ascii'), data]);
  const crc = Buffer.alloc(4);
  crc.writeUInt32BE(zlib.crc32 ? zlib.crc32(body) : 0);
  return Buffer.concat([len, body, crc]);
}

const ihdr = Buffer.alloc(13);
ihdr.writeUInt32BE(1, 0); // width
ihdr.writeUInt32BE(1, 4); // height
ihdr[8] = 8; // bit depth
ihdr[9] = 6; // color type: RGBA (forces pdfkit to decode pixels)
const corruptPng = Buffer.concat([
  Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
  chunk('IHDR', ihdr),
  chunk('IDAT', Buffer.from([0xde, 0xad, 0xbe, 0xef])), // garbage deflate data
  chunk('IEND', Buffer.alloc(0)),
]);

const doc = new PDFDocument();
doc.pipe(fs.createWriteStream('/dev/null'));

try {
  doc.image(corruptPng, 0, 0);
  doc.end();
} catch (err) {
  console.log('Caught:', err.message); // never reached
}

Result: despite the try-catch, the Node process crashes.

Environment: pdfkit 0.19.1, png-js 1.1.0, Node.js 22

Suggested fix

The cleanest option is probably to replace png-js with a maintained decoder such as fast-png, which decodes synchronously, throws normal catchable errors, and seems to be more actively maintained.

Alternatively, fixing png-js itself would be fine too, of course, and I think that the fix would be small. However, this exact problem has already been reported in that repo many years ago (foliojs/png.js#14) and the repository shows little activity, so a fix on the pdfkit side seems more realistic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions