Every object has a __proto__ (or prototype) property too which points to that object’s ‘prototype’, allowing it to inherit properties and methods.
If we try to access a property that doesn’t exist on my_object, JavaScript will next look to see if it is part of the next Object’s proto property
empty_object = {} Object.prototype.x ='test'console.log(empty_object.x) // test
// Empty object. blank_object = {} // Object with a few propertiesmy_object = {a:1, b:2} // Define the 'z' property on the '__proto__' object of 'my_object': my_object["__proto__"]["z"] ="test"console.log(my_object.z) // Output: testconsole.log(blank_object.z) // Output: testconsole.log(Object.z) // Output: test// Note: here we add a 'z' property on the __proto__ object of 'my_object',// that in this case is "Object".
s ="test"s.__proto__// String { .... }// Define the 'z' property on the '__proto__' object of 's': s["__proto__"]["z"] ="bar"console.log(s.z) // Output: bar// Create another string ...x ="test"console.log(x.z) // Output: bar// Create an object ...obj = {}console.log(obj.z) // Output: undefined// Here we add a 'z' property on the __proto__ object of 's',// that in this case is "String". So now all object all objects // that inherit "String" object have this property.
Prototype pollution sources
The three most common JavaScript patterns that can lead to prototype pollution are merging, cloning, and value setting operations. Anytime an object is dynamically built from user input, there's a risk of prototype pollution.
Real World Example – jQuery Deparam
to do
Client-side prototype pollution (manual)
Finding sources
In the URL
Using a common XSS source, such as the URL parameters or hash, set a __proto__ payload, like this:
https://example.com/?__proto__[polluted]=Polluted
// or
https://example.com/#__proto__[polluted]=Polluted
// or
https://example.com/?__proto__.polluted=Polluted
Check Object.prototype in your browser console to see if the property was successfully added:
An important point is that the [] and . notations are not valid JavaScript in this context; they are defined by the developer. So the pattern you should look for in any source is ‘nesting’
An easy trap for developers is overlooking that a JavaScript for...in loop iterates over all of an object's enumerable properties, including inherited ones from the prototype chain.
// Example with "object"constmyObject= { a:1, b:2 };// pollute the prototype with an arbitrary propertyObject.prototype.foo ='bar';// confirm myObject doesn't have its own foo propertymyObject.hasOwnProperty('foo'); // false// list names of properties of myObjectfor(constpropertyKeyin myObject){console.log(propertyKey);}// Output: a, b, foo
// Example with "array"constmyArray= ['a','b'];Object.prototype.foo ='bar';for(constarrayKeyin myArray){console.log(arrayKey);}// Output: 0, 1, foo
Warning: It's easy to unintentionally cause a denial-of-service (DoS), making testing in production risky. In addition, once a server-side prototype is polluted, the change persists for the entire lifetime of the Node process, with no way to reset it.
Detection - (polluted property reflection)
Attempt to pollute the global Object.prototype with an arbitrary property in a POST / PUT request
POST /user/update HTTP/1.1Host:vulnerable-website.com...{"user":"ithomas","firstName":"isaiah","lastName":"thomas","__proto__":{"foo":"bar" }}