CVE-2023-30533 - Exploiting Prototype Pollution in SheetJS Community Edition Before .19.3

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