Security ⚑ High severity

Prototype Pollution

Attacker-controlled JSON input modifies Object.prototype via __proto__, constructor, or prototype keys.

JavaScript’s prototype chain lets every object inherit from `Object.prototype`. Prototype pollution happens when attacker-controlled input — often from `__proto__`, `constructor`, or `prototype` keys in JSON/YAML parsed from untrusted sources — modifies `Object.prototype` itself. Every object in your application then inherits the attacker’s injected property, bypassing checks that assume unknown properties don’t exist.

❌ Vulnerable
// VULNERABLE — user input directly merged into object
const payload = JSON.parse(req.body.data);
const config = { ...defaults, ...payload }; // __proto__ or constructor.prototype pollutes Object.prototype
if (config.isAdmin) { /* bypass auth */ }
✓ Fixed
// FIXED — sanitize dangerous keys
const payload = JSON.parse(req.body.data);
const FORBIDDEN = ['__proto__', 'constructor', 'prototype'];
const safe = Object.fromEntries(
  Object.entries(payload).filter(([k]) => !FORBIDDEN.includes(k))
);
const config = { ...defaults, ...safe };
Multiple real cases — CVE-2025-13465 (Lodash _.zipObjectDeep), CVE-2023-26113 (collection.js), CVE-2024-21505 (web3-utils), CVE-2025-57820 (devalue), CVE-2020-7699 (express-fileupload bypassed original fix using constructor.prototype). React2Shell (CVE-2025-55182) used prototype pollution to achieve RCE via child_process.execSync.
PullLight flags JSON.parse of untrusted input followed by object spread or Object.assign without sanitization of `__proto__`, `constructor`, and `prototype` keys. It detects unsafe `deepmerge` or object spread patterns where external data flows directly into shared object state.
See it in action — paste a diff into /analyze
Try a vulnerable example: pool.query(`SELECT * FROM users WHERE id = ${req.params.id}`)
Analyze a diff →