Prototype Pollution
Attacker-controlled data used to set a property on Object.prototype itself, affecting every plain object in the program — distinct from DOM XSS.
Purpose
Prototype pollution happens when attacker-controlled data walks into a merge, assign, or clone
operation that doesn’t filter special keys — reaching and mutating Object.prototype itself, which
every plain object in the program inherits from.
Example
function merge(target, source) {
for (const key in source) {
if (typeof source[key] === 'object') {
target[key] = merge(target[key] || {}, source[key]);
} else {
target[key] = source[key];
}
}
return target;
}
const malicious = JSON.parse('{"__proto__": {"isAdmin": true}}');
merge({}, malicious);
({}).isAdmin; // true — every plain object now has this, program-wide
Behavior notes
- The attack works by walking
__proto__as an ordinary enumerable key — most naive merge/deep-clone implementations don’t special-case it. - The impact depends entirely on what the rest of the application does with the polluted
prototype — it doesn’t execute code directly, but can corrupt logic that checks a property
assumed to be absent (
if (user.isAdmin)) anywhere in the program. Object.create(null)or aMapavoids the risk entirely for genuinely untrusted key-value data, since neither has a prototype chain a__proto__key could reach.
Common mistakes
- Assuming input validation aimed at DOM XSS (escaping HTML) also protects against prototype pollution — they’re unrelated risk classes requiring separate defenses.
- Writing a custom merge/deep-clone utility without an explicit denylist for
__proto__,constructor, andprototype.
Runtime notes
Applies to any JavaScript environment with the standard prototype-chain object model — browser and Node code are both affected equally.