xlsx CVE-2023-30533 · CVE-2024-22363
Prototype pollution and ReDoS in SheetJS xlsx on file read.
The problem
xlsx <= 0.18.5 on npm (the last npm-published release) is affected by
CVE-2023-30533, CVE-2024-22363 (CWE-1321 Prototype Pollution / CWE-1333 ReDoS). The published package has
no fix available — exactly what npm audit reports. Two vulnerabilities are reachable when `XLSX.read()` parses an attacker-supplied spreadsheet. CVE-2023-30533: a crafted (threaded) comment whose cell `ref` is `__proto__` causes `sheet[ref]` to resolve to `Object.prototype`, which is then mutated — polluting every object in the process. CVE-2024-22363: a crafted `docProps/core.xml` with many unclosed property tags triggers catastrophic backtracking in the core-property regex (a ~2 MB file takes ~50 seconds to parse, a denial of service).
The fix — drop-in, no code changes
Add an overrides entry so every direct and transitive dependency on
xlsx resolves to the patched fork, then reinstall:
{
"overrides": {
"xlsx": "npm:@keep-lts/xlsx@^0.18.6"
}
}
Equivalent for Yarn: use resolutions. The public API is unchanged — nothing else to do.
✓ Live on npm: @keep-lts/xlsx · or install directly: npm i @keep-lts/xlsx
What we changed
Prototype pollution: `sheet_insert_comments` now returns early when `decode_cell(comment.ref)` yields negative row/column, so a non-address ref such as `__proto__` can never reach `sheet[comment.ref]`. ReDoS: `parse_core_props` now locates each property tag with `String#indexOf` (`str_match_xml`) instead of a `([\s\S]*?)` regex that re-scanned from every opening tag. Both are direct ports of SheetJS's own fixes; a cross-version equivalence test confirms legitimate files parse identically to upstream 0.18.5.
Proof of concept (the vulnerability)
const XLSX = require('xlsx');
// 1) prototype pollution
XLSX.read(fs.readFileSync('threaded_comment_bad.xlsx')); // sets Object.prototype.c on 0.18.5
// 2) ReDoS: a docProps/core.xml with 128k unclosed <dcterms:created> tags
XLSX.read(crafted_buffer, { type: 'buffer' }); // ~50s on 0.18.5, ~17ms when patched
@keep-lts/xlsx@0.18.6How we keep it trustworthy
- Minimal, surgical patch — security only, no feature changes.
- A regression test that fails on the original and passes on the patch; legitimate behaviour preserved.
- Published under the
@keep-ltsorg with the full advisory and tests inside the package; upstream license & attribution retained.
Full advisory and changelog ship inside the package (SECURITY.md, CHANGELOG.md).