Skip to content

CVE-2026-8813: Verified Repro With Script Download

CVE-2026-8813: ExifReader: unbounded memory amplification DoS via crafted ICC mluc tag

CVE-2026-8813 is verified against exifreader · npm. Affected versions: < 4.39.0. Fixed in 4.39.0. Vulnerability class: DoS. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00137.

REPRO-2026-00137 exifreader · npm DoS May 22, 2026 CVE entry ↗ .txt
Severity
HIGH
CVSS
7.5
Reproduced in
35m 45s
Tool calls
158
Spend
$2.06
01 · Overview

What Is CVE-2026-8813?

CVE-2026-8813 is a high-severity denial-of-service vulnerability in the ExifReader JavaScript library caused by unbounded memory amplification when parsing a crafted ICC color-profile mluc tag. Pruva reproduced it (reproduction REPRO-2026-00137).

02 · Severity & CVSS

CVE-2026-8813 Severity & CVSS Score

CVE-2026-8813 is rated high severity, with a CVSS base score of 7.5 out of 10.

HIGH threat level
7.5 / 10 CVSS base
Weakness CWE-1284

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected exifreader Versions

exifreader · npm versions < 4.39.0 are affected.

How to Reproduce CVE-2026-8813

$ pruva-verify REPRO-2026-00137
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00137/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-8813

Reproduced by Pruva's autonomous agents — 158 tool calls over 36 min. Full root-cause analysis and the complete transcript are below.

How the agent worked 578 events · 158 tool calls · 36 min
36 minDuration
158Tool calls
139Reasoning steps
578Events
Agent activity over 36 min
Support
26
Repro
113
Variant
434
0:0035:45

Root Cause and Exploit Chain for CVE-2026-8813

Summary

ExifReader versions prior to 4.39.0 contain a denial-of-service vulnerability in their ICC profile parser. When parsing a crafted ICC profile containing an mluc (multi-localized Unicode) tag with a zero recordSize and a very large numRecords value, the parser enters an unbounded loop that repeatedly appends entries to an output array without advancing the read cursor. This causes unbounded memory growth (memory amplification), eventually exhausting the JavaScript heap and triggering an out-of-memory (OOM) crash.

Impact

  • Package/component affected: exifreader npm package (ICC tag parsing module, specifically src/icc-tags.js)
  • Affected versions: < 4.39.0 (vulnerable), specifically tested on 4.38.1
  • Fixed versions: 4.39.0
  • Risk level and consequences: High (CVSS 3.1 base 7.5). Any application that parses attacker-supplied images using ExifReader (image upload endpoints, thumbnailers, metadata extractors) can be crashed remotely by a single crafted ~220-byte JPEG file. The impact is a complete denial of service via process OOM.

Root Cause

The vulnerability exists in src/icc-tags.js in the parseTags function, specifically in the TAG_TYPE_MULTI_LOCALIZED_UNICODE_TYPE (mluc) handling branch. The vulnerable code (from v4.38.1) reads two attacker-controlled 32-bit fields from the ICC profile buffer:

  1. numRecords at tagOffset + 8
  2. recordSize at tagOffset + 12

It then enters a for loop that iterates numRecords times. On each iteration it reads a record from offset, pushes a parsed entry object into the val array, and then advances offset += recordSize. When recordSize is zero, offset never advances, so the same bytes are re-read on every iteration. Because numRecords is also attacker-controlled (e.g., 10,000,000), the loop runs unboundedly, appending millions of objects to the val array and causing catastrophic heap growth.

Additionally, even if recordSize is non-zero but large, the loop could read beyond the buffer bounds, although the zero-record-size case is the most direct amplification vector.

The fix commit c9d88b67e127b2dcc7b46e328df468257fb2dc30 adds two validations before entering the mluc loop:

  1. A minimum record-size check: recordSize < 12 (the size of a single record) causes an early return.
  2. A bounds check: numRecords * recordSize must not exceed the remaining buffer length after the mluc header (dataView.byteLength - tagOffset - 16).

These checks prevent both the zero-record-size infinite loop and the out-of-bounds over-read scenarios.

Reproduction Steps

The reproduction is fully automated in repro/reproduction_steps.sh.

What the script does:

  1. Installs exifreader@4.38.1 (vulnerable) and exifreader@4.39.0 (fixed) into separate temporary directories.
  2. Constructs a minimal 220-byte JPEG containing an APP0 JFIF segment and an APP2 ICC profile segment.
  3. The embedded ICC profile is 180 bytes and contains:
    • A valid acsp signature.
    • One tag-table entry pointing to an mluc tag at offset 144.
    • The mluc tag declares numRecords = 10,000,000 and recordSize = 0.
  4. Runs a Node.js harness against the malicious image for each version, capping the heap at 128 MB and enforcing a 10-second timeout.
  5. Compares exit codes, duration, and memory growth.

Expected evidence:

  • Vulnerable (4.38.1): The Node.js process OOM-crashes within ~1.5 seconds with exit code 134 (FATAL ERROR: Ineffective mark-compacts near heap limit).
  • Fixed (4.39.0): The parse completes successfully in ~3–4 ms with ~1.25 MB RSS growth, returning the parsed ICC header tags and skipping the malformed mluc tag.

Evidence

  • Log directory: logs/
  • logs/npm_install_vuln.log / logs/npm_install_fix.log — package installation output
  • logs/vuln_out.txt — OOM stack trace from the vulnerable version:
    FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
    
  • logs/fix_out.txt — successful parse output from the fixed version:
    SUCCESS duration_ms=4 delta_rss_mb=1.25
    
  • Environment: Node.js v22.22.2 on Linux x64.
  • Idempotency: The reproduction script was executed twice consecutively with identical results.

Recommendations / Next Steps

  1. Upgrade immediately to exifreader@4.39.0 or later. The patch is a minimal, targeted bounds-check addition with no breaking API changes.
  2. Input validation for applications that accept arbitrary user images: consider pre-scanning or sandboxing image parsing operations, and enforce resource limits (CPU time, memory) on metadata-extraction workers.
  3. Regression testing: Add a unit test that feeds the same 220-byte malicious JPEG to ExifReader.load() and asserts that it returns within a short timeout and without excessive memory growth.
  4. Audit related parsers: Check other tag-type parsers in src/icc-tags.js (e.g., desc, text, sig) for similar missing bounds checks.

Additional Notes

  • The crafted image file is only 220 bytes, yet it can crash a Node.js process with a 128 MB heap limit in under 2 seconds. This demonstrates the severity of memory-amplification bugs.
  • The reproduction is fully idempotent: repro/reproduction_steps.sh cleans up its temporary directories on exit and can be re-run from any working directory.
  • The script uses NODE_PATH injection to load the correct exifreader version without conflicting installations, ensuring clean isolation between the vulnerable and fixed test cases.

CVE-2026-8813 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:001:26
0:00
session startedaccounts/fireworks/models/kimi-k2p6 · cve-2026-8813 · cve-2026
0:06
0:07
web search
0:10
0:11
web search
0:14
0:15
0:38
web search
0:46
0:47
0:48
web search
1:19
1:19
extract_facts
no facts extracted
1:21
1:21
1:21
supportrepro
1:23
1:23
1:23
1:25
1:25
1:25
1:26

Artifacts and Evidence for CVE-2026-8813

Scripts, logs, diffs, and output captured during the reproduction.

No artifacts available

08 · How to Fix

How to Fix CVE-2026-8813

Upgrade exifreader · npm to 4.39.0 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-8813 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-8813

How does the CVE-2026-8813 memory amplification attack work?

A crafted mluc tag sets a very large numRecords and a recordSize of zero. Because the record size is zero, the read cursor never advances, so the parsing loop reprocesses the same record and appends an output entry on every one of the numRecords iterations — a tiny ~220-byte crafted JPEG can inflate into hundreds of megabytes to gigabytes of allocations, exhausting the JavaScript heap and crashing the process with an OOM error.

Which ExifReader versions are affected by CVE-2026-8813, and where is it fixed?

Versions before 4.39.0 are affected (tested on 4.38.1); it is fixed in 4.39.0.

How severe is CVE-2026-8813?

It is rated high severity (CVSS 3.1 base 7.5): any application that parses attacker-supplied images with ExifReader (image upload endpoints, thumbnailers, metadata extractors) can be crashed remotely by a single crafted image.

How can I reproduce CVE-2026-8813?

Download the verified script from this page and run it in an isolated environment against ExifReader 4.38.1. It parses a crafted ~220-byte JPEG whose embedded ICC profile has an mluc tag with a huge record count and zero record size, and shows Node.js process memory growing unboundedly, then confirms 4.39.0 rejects the malformed tag safely.
11 · References

References for CVE-2026-8813

Authoritative sources for CVE-2026-8813 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.