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
This is rarely the only one
If xlsx turned up in your npm audit, there are very likely other abandoned dependencies in the same tree whose CVEs also have no fix on npm. Send us your npm audit output — or your Snyk / Dependabot list — and we'll tell you, for free, which of those findings we already fix. No call, no obligation.
Mid-audit and need a vendor on the hook? Keep LTS Pro adds an SLA on future CVEs and the SBOM / VEX artefacts your auditor will accept — all async, no calls.
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).