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.
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).
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 — serious impact or readily exploitable. Prioritize remediation.
Affected exifreader Versions
exifreader · npm versions < 4.39.0 are affected.
How to Reproduce CVE-2026-8813
pruva-verify REPRO-2026-00137 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00137/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh 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
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:
exifreadernpm package (ICC tag parsing module, specificallysrc/icc-tags.js) - Affected versions:
< 4.39.0(vulnerable), specifically tested on4.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:
numRecordsattagOffset + 8recordSizeattagOffset + 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:
- A minimum record-size check:
recordSize < 12(the size of a single record) causes an early return. - A bounds check:
numRecords * recordSizemust not exceed the remaining buffer length after themlucheader (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:
- Installs
exifreader@4.38.1(vulnerable) andexifreader@4.39.0(fixed) into separate temporary directories. - Constructs a minimal 220-byte JPEG containing an APP0 JFIF segment and an APP2 ICC profile segment.
- The embedded ICC profile is 180 bytes and contains:
- A valid
acspsignature. - One tag-table entry pointing to an
mluctag at offset 144. - The
mluctag declaresnumRecords = 10,000,000andrecordSize = 0.
- A valid
- Runs a Node.js harness against the malicious image for each version, capping the heap at 128 MB and enforcing a 10-second timeout.
- 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
mluctag.
Evidence
- Log directory:
logs/ logs/npm_install_vuln.log/logs/npm_install_fix.log— package installation outputlogs/vuln_out.txt— OOM stack trace from the vulnerable version:FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memorylogs/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
- Upgrade immediately to
exifreader@4.39.0or later. The patch is a minimal, targeted bounds-check addition with no breaking API changes. - 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.
- 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. - 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.shcleans up its temporary directories on exit and can be re-run from any working directory. - The script uses
NODE_PATHinjection to load the correctexifreaderversion 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.
Artifacts and Evidence for CVE-2026-8813
Scripts, logs, diffs, and output captured during the reproduction.
No artifacts available
How to Fix CVE-2026-8813
Upgrade exifreader · npm to 4.39.0 or later.
FAQ: CVE-2026-8813
How does the CVE-2026-8813 memory amplification attack work?
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?
How severe is CVE-2026-8813?
How can I reproduce CVE-2026-8813?
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.