diff --git a/advisories/unreviewed/2026/05/xlsx-cdata-recursion-cve-2026-38358/xlsx-cdata-recursion-cve-2026-38358.json b/advisories/unreviewed/2026/05/xlsx-cdata-recursion-cve-2026-38358/xlsx-cdata-recursion-cve-2026-38358.json new file mode 100644 index 0000000000000..3123b2017f521 --- /dev/null +++ b/advisories/unreviewed/2026/05/xlsx-cdata-recursion-cve-2026-38358/xlsx-cdata-recursion-cve-2026-38358.json @@ -0,0 +1,69 @@ +{ + "schema_version": "1.4.0", + "id": "xlsx-cdata-recursion-cve-2026-38358", + "modified": "2026-05-07T00:00:00Z", + "published": "2026-05-07T00:00:00Z", + "aliases": [ + "CVE-2026-38358" + ], + "summary": "xlsx (SheetJS Community Edition): Unbounded recursion in unescapexml() leads to remote DoS via crafted XLSX files", + "details": "## Summary\n\nSheetJS xlsx Community Edition (all versions including 0.18.5, unmaintained since 2022) contains an unbounded recursion vulnerability in the XML parser's `unescapexml()` function. A crafted XLSX file containing many sequential `` tokens in `xl/sharedStrings.xml` causes recursive calls to exhaust the JavaScript call stack, terminating the Node.js process.\n\n**The package is unmaintained.** Users should migrate to `xlsx-js-style` or `exceljs`.\n\n## Vulnerable code (`xlsx.js:3501-3506`)\n\n```javascript\nreturn function unescapexml(text) {\n var s = text + '';\n var i = s.indexOf(\"\");\n return unescapexml(s.slice(0, i)) + // Recurse on prefix\n s.slice(i+9, j) + // Raw CDATA content\n unescapexml(s.slice(j+3)); // Recurse on suffix — UNBOUNDED\n};\n```\n\n## Recursion mechanics\n\n- Each `` token in the string triggers one recursive call on the suffix\n- N sequential tokens = N stack frames\n- JavaScript does not tail-call optimize this pattern\n- No depth counter or iteration limit exists\n\n**Call chain:**\n```\nXLSX.read(buffer)\n → parse_zip()\n → parse_sst_xml() // Shared Strings Table\n → unescapexml(text)\n → unescapexml(suffix) → Recurses N times for N CDATA tokens\n```\n\n## Proof of Concept\n\nAn XLSX file (~126 KB) containing `xl/sharedStrings.xml` with approximately 9,000 sequential `` tokens reliably triggers `RangeError: Maximum call stack size exceeded` on Node.js v18+. Crash threshold: ~8,320 tokens (varies by Node.js version).\n\n## Impact\n\nAny application that processes untrusted XLSX files using SheetJS Community Edition is vulnerable. Attack scenarios:\n\n- Web application file upload endpoints accepting `.xlsx`\n- Email gateway scanners auto-processing attachments\n- REST/GraphQL APIs with Excel import functionality\n- Cloud storage with automatic file processing pipelines\n- Batch ETL/data processing pipelines accepting partner-supplied XLSX files\n\nResult: Node.js process termination, denial of service for the affected service.\n\n## Mitigation\n\nNo patch will be released — SheetJS Community Edition is unmaintained.\n\n**Migrate to:**\n- `xlsx-js-style` (community fork of older sheetjs)\n- `exceljs` (actively maintained alternative)\n\nIf migration is not immediately possible:\n- Reject XLSX uploads larger than a strict size threshold (e.g. 1 MB)\n- Pre-scan `xl/sharedStrings.xml` for excessive CDATA token counts before calling `XLSX.read()`\n- Process XLSX parsing in a worker thread or sandboxed subprocess", + "severity": [ + { + "type": "CVSS_V3", + "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H" + } + ], + "affected": [ + { + "package": { + "ecosystem": "npm", + "name": "xlsx" + }, + "ranges": [ + { + "type": "ECOSYSTEM", + "events": [ + { + "introduced": "0" + } + ] + } + ], + "database_specific": { + "last_known_affected_version_range": "<= 0.18.5" + } + } + ], + "references": [ + { + "type": "ADVISORY", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-38358" + }, + { + "type": "PACKAGE", + "url": "https://github.com/SheetJS/sheetjs" + }, + { + "type": "WEB", + "url": "https://www.npmjs.com/package/xlsx" + }, + { + "type": "WEB", + "url": "https://www.npmjs.com/package/xlsx-js-style" + }, + { + "type": "WEB", + "url": "https://www.npmjs.com/package/exceljs" + }, + { + "type": "WEB", + "url": "https://cwe.mitre.org/data/definitions/674.html" + } + ], + "database_specific": { + "cwe_ids": [ + "CWE-674" + ] + } +}