Are you using the popular SheetJS Community Edition (xlsx npm package) for processing Excel files in your web apps or Node.js projects? If so, you need to know about a dangerous vulnerability tracked as CVE-2023-30533—especially if your version is *older than .19.3*.
In this exclusive post, we’ll break down, in simple language, how this vulnerability works, show you scary code snippets that demonstrate the problem, and explain what to do to *protect your users*.
What Is Prototype Pollution?
Before we get into the SheetJS issue, let’s recap prototype pollution. In JavaScript, objects inherit properties and methods from their “prototype” (Object.prototype). Prototype pollution is when a bad actor injects properties into JavaScript’s base Object prototype using crafted input. This can:
SheetJS Prototype Pollution: The Details
Earlier versions of SheetJS Community Edition (< .19.3) allowed attackers to upload malicious XLSX files that inject dangerous properties into objects created by SheetJS. When you load these poisoned files, your app’s global object can be polluted.
*Original Reference*
- GitHub Security Advisory GHSA-r6w7-6mxw-94pq
- NVD’s CVE-2023-30533 Page
How the Exploit Works
SheetJS parses Excel files, turning cell data into JavaScript objects. In old versions, it doesn’t properly filter out dangerous keys like __proto__ that are used for prototype pollution.
An attacker could create a specially crafted Excel file (actually, just a ZIP file with custom content for the XLSX format) that, once loaded, injects malicious key(s) into your app.
Proof-of-Concept: Code Snippet
Let’s see what this *really* looks like. Here’s a classic example (for educational purposes only):
const XLSX = require('xlsx'); // Version <= .19.2 is vulnerable
const fs = require('fs');
const maliciousBuffer = fs.readFileSync('malicious.xlsx'); // Malicious file crafted by attacker
const workbook = XLSX.read(maliciousBuffer, { type: "buffer" });
console.log({}.polluted);
// If prototype pollution happened and attacker set __proto__.polluted = "pwned", this will print "pwned"!
Here’s the malicious part: the crafted XLSX file contains JSON or zip entry crafting so that SheetJS ends up doing something like:
Object.assign({}, {"__proto__": {"polluted": "pwned"}});
Now, every object in your code inherits the property polluted: "pwned"!
While we won’t show you a complete binary XLSX payload, the idea is
- In the sharedStrings.xml or custom properties of the file, insert elements like <si><t>__proto__</t></si> with a value.
So, a quick way in JavaScript
// bad.json payload for demonstration
{ "__proto__": { "polluted": "true" } }
If SheetJS reads any part of an object with __proto__ as a property, the pollution occurs.
Imagine this in your serverless function, backend API, or even a web browser! Here’s a quick proof
const innocentObject = {};
console.log(innocentObject.polluted); // before: undefined
// Load the malicious file here (see above)
console.log(innocentObject.polluted); // after: "pwned" (attacker’s data)
Now, your app might accidentally trust this property, alter logic, or leak sensitive info.
If your project uses SheetJS *before version .19.3*, upgrade now
npm install xlsx@latest
The maintainers patched the issue in version .19.3 by filtering dangerous keys like __proto__ and constructor.
- Patch Pull Request
Conclusion
CVE-2023-30533 is a classic example of why *object property pollution* is a serious web security risk—especially in popular tools like SheetJS. Don’t let your application be the next victim. Patch now, and audit your third-party dependencies regularly!
For more, check out
- Original Advisory (SheetJS GHSA)
- Snyk’s Report
Timeline
Published on: 04/24/2023 08:15:00 UTC
Last modified on: 05/02/2023 18:40:00 UTC