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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions