Prototype Pollution Attacks
HardPrototype pollution is a security vulnerability where an attacker manipulates the prototype chain to inject malicious properties. This can lead to denial of service, property injection, or even remote code execution. It commonly occurs when merging or cloning objects without proper key validation, especially with user-controlled input.
Interactive Visualization
Code
1const user = { name: "Alice" }
2const config = { theme: "dark" }
3
4user.isAdmin // undefined
5config.isAdmin // undefined
6
7// Both objects are clean - no isAdmin property
Objects
user
name:"Alice"
__proto__: → Object.prototype
config
theme:"dark"
__proto__: → Object.prototype
Object.prototype
toString:fn()
Normal state - two clean objects with their own properties
Output:
undefined
undefined
1 / 4
Key Insight: Modifying Object.prototype affects ALL objects. Always use Object.hasOwn() to distinguish own properties from inherited ones.
Key Points
- Attacker injects properties via __proto__, constructor, or prototype
- Affected operations: merge, clone, extend, deep assign
- Can affect all objects if Object.prototype is polluted
- Prevention: validate keys, use Object.create(null), freeze
- Famous in lodash merge, jQuery extend, etc.
Code Examples
The Attack Vector
// Vulnerable merge function function merge(target, source) { for (let key in source) { if (typeof source[key] === 'object') { if (!target[key]) target[key] = {}; merge(target[key], source[key]); } else { target[key] = source[key]; } } return target; } // Attacker input const malicious = JSON.parse('{ "__proto__": { "isAdmin": true } }'); const victim = {}; merge(victim, malicious); // All objects now have isAdmin: true! console.log({}.isAdmin); // true 😱 // The attack: // merge follows __proto__ and sets {}.__proto__.isAdmin // This modifies Object.prototype!
Attacker uses __proto__ key to inject properties onto Object.prototype, affecting all objects.
Prevention
// Safe merge - skip dangerous keys function safeMerge(target, source) { for (let key in source) { // Skip prototype pollution keys if (key === '__proto__' || key === 'constructor' || key === 'prototype') { continue; } if (typeof source[key] === 'object') { if (!target[key]) target[key] = {}; safeMerge(target[key], source[key]); } else { target[key] = source[key]; } } return target; } // Or use Object.create(null) for maps const safeMap = Object.create(null); safeMap["__proto__"] = "value"; // Just a property, not the prototype // Or freeze Object.prototype Object.freeze(Object.prototype);
Prevent by: 1) Skipping dangerous keys, 2) Using Object.create(null), 3) Freezing Object.prototype.
Common Mistakes
- Not validating keys in merge/clone functions
- Using user input directly in object property names
- Not knowing about Object.freeze(Object.prototype) as protection
Interview Tips
- Know what prototype pollution is
- Know the dangerous keys: __proto__, constructor, prototype
- Know prevention techniques
- Be aware of affected libraries (lodash < 4.17.12)