In client-side JavaScript, this commonly leads to DOM XSS, while server-side prototype pollution can even result in remote code execution.

Prototype pollution is often unexploitable as a standalone vulnerability. If the application subsequently handles an attacker-controlled property in an unsafe way, this can potentially be chained with other vulnerabilities.
Let’s first learn what is a prototype and __proto__:
In JavaScript, a prototype is an object that is associated with every constructor function and object in the language. It serves as a blueprint for creating new instances of objects with predefined properties and methods.
When you create a constructor function or an object literal in JavaScript, an internal property called [[Prototype]]
(also referred to as __proto__
) is automatically assigned to it. This [[Prototype]]
property references the prototype object associated with the constructor function or the object.
The prototype object contains properties and methods that are shared among all instances created from the constructor function or the object. When you access a property or method on an instance, JavaScript first looks for it on the instance itself. If it doesn’t find it, it then looks for it in the prototype object ([[Prototype]]
). If it still doesn't find it, it continues to search up the prototype chain until it reaches the top-level Object.prototype
.
Here’s an example to illustrate this concept:
// Constructor function
function Person(name) {
this.name = name;
}
// Adding a method to the prototype
Person.prototype.greet = function() {
console.log('Hello, my name is ' + this.name);
};
// Creating an instance
var person1 = new Person('Alice');
// Accessing instance property
console.log(person1.name); // Output: Alice
// Accessing instance method
person1.greet(); // Output: Hello, my name is Alice
// Accessing property/method via prototype
console.log(person1.__proto__ === Person.prototype); // Output: true
In the example above, the Person
constructor function creates instances with a name
property. The greet
method is added to the prototype of Person
. When you create a new instance (person1
) and access its properties or methods, JavaScript first checks the instance itself. If the property or method is not found, it looks up the prototype chain ([[Prototype]]
) and finds it in Person.prototype
.


Now let’s see “What is prototype pollution?”:
In JavaScript, objects are created based on a prototype, which serves as a template for defining the object’s properties and methods. When a property or method is accessed on an object, JavaScript looks up the prototype chain to find the appropriate definition.
Prototype pollution occurs when an attacker is able to inject or modify properties on an object’s prototype, thereby affecting all instances and future instances of that object. This pollution can lead to various security issues, such as:
- Property overriding: By modifying the prototype, an attacker can add or modify properties of an object that may impact the object’s intended behavior. This can lead to unexpected or insecure behavior when the object is used elsewhere in the codebase.
- Property shadowing: An attacker can add properties to the prototype with the same name as existing properties in the object. This can cause the properties in the prototype to shadow the original properties, leading to unintended behavior when accessing those properties.
- Denial of Service (DoS): By polluting certain properties or methods, an attacker can manipulate the behavior of the affected code to cause excessive memory consumption or infinite loops, resulting in a denial of service condition.
Prototype pollution attacks typically rely on user-controlled input that is not properly validated or sanitized. For example, if a JavaScript application processes external data without adequate checks, it may inadvertently allow an attacker to manipulate the prototype and exploit the vulnerability.
When a JavaScript function recursively merges an object containing user-controllable properties into an existing object, without first sanitizing the keys. This can allow an attacker to inject a property with a key like __proto__
, along with arbitrary nested properties.
It’s possible to pollute any prototype object, but this most commonly occurs with the built-in global Object.prototype
.
Client-side prototype pollution via browser APIs:

This may initially seem like a reasonable mitigation attempt as this prevents the vulnerable object from inheriting a malicious version of the gadget property via the prototype chain. However, this approach is inherently flawed.
Object.defineProperty()
accepts an options object, known as a "descriptor". Among other things, developers can use this descriptor object to set an initial value for the property that’s being defined. However, if the only reason that they’re defining this property is to protect against prototype pollution, they might not bother setting a value at all.
In this case, the code is targeting the transport_url
property of the config
object. It sets the configurable
attribute to false
, which means that the property cannot be deleted, and the writable
attribute to false
, which means that the value of the property cannot be changed.
The code doesn’t define a value for the transport_url
property. In JavaScript, if you don't provide a value when defining a property using Object.defineProperty()
, the property's value is set to undefined
by default.
In this case, an attacker may be able to bypass this defense by polluting Object.prototype
with a malicious value
property. If this is inherited by the descriptor object passed to Object.defineProperty()
, the attacker-controlled value may be assigned to the gadget property after all.



The payload uses a data
URL as the value for the __proto__[value]
parameter. The data
URL scheme allows you to include data directly in the URL itself. In this case, the payload is utilizing a data
URL to inject JavaScript code for an XSS (Cross-Site Scripting) proof-of-concept.
The data
URL scheme allows you to specify the data directly after the data:
prefix. By injecting the data
URL payload as the value for this parameter, the JavaScript code alert(1)
gets executed within the application's context, causing the pop-up alert to appear.
DOM Invader
DOM Invader is a browser-based tool that helps you test for DOM XSS vulnerabilities using a variety of sources and sinks, including both web message and prototype pollution vectors. It is available exclusively via Burp’s built-in browser, where it comes preinstalled as an extension.


Comments
Post a Comment