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.
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-jsdependency. IndecodePixels, it callszlib.inflateand re-throws the error from inside the asynchronous callback: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:
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-jswith a maintained decoder such asfast-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.