+ "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 `<![CDATA[...]]>` 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(\"<![CDATA[\");\n if(i == -1) return s.replace(encregex, ...).replace(coderegex, ...);\n\n var j = 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 `<![CDATA[...]]>` 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 `<![CDATA[a]]>` 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",
0 commit comments