{
  "ticket_id": "CVE-2026-8813",
  "code_root": "external/exifreader",
  "source": {
    "type": "cve",
    "cve_id": "CVE-2026-8813",
    "vendor": "mattiasw",
    "product": "ExifReader",
    "repo": "https://github.com/mattiasw/ExifReader"
  },
  "facts": {
    "cve_id": "CVE-2026-8813",
    "issue_summary": "Memory-amplification denial of service in the ExifReader npm package. When parsing an image's embedded ICC profile, the parser handles the 'mluc' (multi-localized Unicode) tag by reading an attacker-controlled record count and record size from the profile data. Through version 4.38.1 the parser does not validate these fields against the actual buffer bounds: a crafted ICC 'mluc' tag that declares a very large record count together with a record size of zero causes the parser to repeatedly reprocess the same record and append entries to its output without bound, exhausting process memory until the Node.js process is OOM-killed.",
    "vulnerability_type": "Improper Bounds Validation -> Memory-Amplification Denial of Service",
    "suspected_cwe": ["CWE-1284", "CWE-789"],
    "affected_versions": "< 4.39.0",
    "fixed_versions": ["4.39.0"],
    "reproduce_version": "4.38.1",
    "verify_fixed_version": "4.39.0",
    "repo_url": "https://github.com/mattiasw/ExifReader.git",
    "fix_commit": "c9d88b67e127b2dcc7b46e328df468257fb2dc30",
    "code_root": "external/exifreader",
    "ecosystem": "npm",
    "package": "exifreader",
    "install_recipe": "In a scratch directory run `npm install exifreader@4.38.1` (vulnerable) or `npm install exifreader@4.39.0` (fixed). The published npm tarball is the canonical artifact; git tags v4.38.1 / v4.39.0 on the repo are equivalent.",
    "attacker_access": "Remote / unauthenticated. Any code path that feeds an attacker-supplied image into ExifReader (e.g. an image-upload endpoint, a thumbnailer, a metadata extractor) is exploitable - the attacker only needs the application to parse one crafted image.",
    "exploit_outline": "Craft a minimal image (e.g. JPEG) carrying an embedded ICC profile that contains an 'mluc'-typed tag. In the mluc tag set the record-count field to a large attacker-controlled value and the record-size field to zero. Feed the crafted image to ExifReader.load()/ExifReader's parser. The mluc parsing loop reprocesses the same zero-length record `count` times, appending an entry each iteration, so output memory grows without bound and process RSS balloons until the Node process is OOM-killed.",
    "vulnerable_indicator": "Parsing the crafted image with exifreader@4.38.1 causes unbounded memory growth: process RSS climbs into the multi-hundred-MB / GB range and the parse never completes normally - it either OOM-kills the Node process (non-zero exit / SIGKILL) or shows measurable multi-hundred-MB RSS growth versus a baseline parse. Capture with `/usr/bin/time -v` (Maximum resident set size) or by sampling `process.memoryUsage().rss` and bounding the parse with a timeout / `--max-old-space-size` cap.",
    "fixed_indicator": "Parsing the same crafted image with exifreader@4.39.0 completes quickly and normally: the mluc record count/size are validated against the buffer bounds, no unbounded loop occurs, the process exits 0 and Maximum resident set size stays small (tens of MB, comparable to a benign parse).",
    "reproduction_requirements": "Node.js (any maintained LTS) plus the exifreader package at the specified version. No network service, database, or browser required - the difference is observable purely in-process by parsing a crafted image buffer and measuring memory. To make the vulnerable case terminate deterministically rather than hang the sandbox, run the vulnerable parse under a memory cap (e.g. `node --max-old-space-size=512`) and/or a timeout so the unbounded growth is observed as an OOM/abort, then contrast with the fixed build completing within the same cap.",
    "notes": "This is a memory-exhaustion DoS, not a crash from malformed input - the distinguishing signal is bounded vs unbounded memory growth. The repro must read the patch in commit c9d88b67e127b2dcc7b46e328df468257fb2dc30 to confirm exactly which mluc bounds check was added and craft the ICC 'mluc' tag (large record count + zero record size) accordingly. Do not rely on a hang; bound the vulnerable run with a memory cap or timeout so the indicator is a clean non-zero exit / measurable RSS delta."
  }
}
