How to prevent prototype pollution vulnerabilities

We recommend patching any prototype vulnerabilities that you identify on your websites, regardless of whether they are coupled with exploitable gadgets. Even if you’re sure you haven’t missed anything, there’s no guarantee that future updates of your own code or the libraries you use won’t introduce new gadgets and pave the way for viable exploits.

In this section, we provide general advice on some of the steps you can take to protect your own websites from the threats we’ve covered in our labs. We’ll also cover some common pitfalls to avoid.

Clean property key

One of the more obvious ways to prevent prototype pollution vulnerabilities is to clean property keys before merging them with existing objects. This way you can prevent an attacker from stealing keys such as __proto__pointing to the prototype of the object.

Using an allow list of allowed keys is the most effective way to do this. However, since this is not feasible in many cases, it is common to use a blacklist instead, which removes potentially dangerous strings from user input.

While this is a quick solution to implement, a truly robust blocklist is inherently difficult, as demonstrated by sites that successfully block __proto__, but do not take into account that an attacker has polluted an object’s prototype via its constructor. For this reason, we only recommend this as a temporary solution and not as a long-term solution.

Weak implementations can also be circumvented. A common mistake is not to recursively clean up the input string. For example, consider the following URL:

READ :  With 13.9% CAGR, Touch Screen Display Market Size worth USD

If the disinfection process only removes the cord __proto__ Without repeating this process more than once, this would result in the following URL, which is a potentially valid prototype pollution source:

Prevent changes to global prototypes

A more robust approach to avoiding prototype pollution vulnerabilities is to prevent global prototypes from being modified in the first place.

Citing the Object.freeze() method on an object ensures that its properties and their values ​​can no longer be modified and no new properties can be added. Since prototypes themselves are just objects, you can use this method to proactively truncate potential sources:


That Object.seal() The method is similar, but still allows changing the values ​​of existing properties. This can be a good compromise if you can’t use it Object.freeze() for any reason.

Prevent an object from inheriting properties

While you can use Object.freeze() To block potential sources of prototype pollution, you can also take steps to eliminate gadgets. Even if an attacker identifies a prototypical pollution vulnerability, it is unlikely to be exploitable in this way.

By default, all objects inherit from the global Object.prototype either directly or indirectly through the prototype chain. However, you can also set the prototype of an object manually by creating it using Object.create() Method. This not only allows you to assign any object as a prototype of the new object, but also to create the object with one null Prototype ensuring it doesn’t inherit any properties at all.

let myObject = Object.create(null);
Object.getPrototypeOf(myObject); // null

Use safer alternatives whenever possible

Another robust protection against contamination from prototypes is to use objects that provide built-in protection. For example, if you are defining an option object, you could use a Map instead of this. Although a card can still inherit malicious traits, they have one built in get() Method that returns only properties defined directly on the card itself:

READ :  Helping to Prevent Threats, Data Breaches & More

let options = new Map();
options.set('transport_url', '');

options.evil; // 'polluted'
options.get('evil'); // undefined
options.get('transport_url'); // ''

A Set is another alternative if you are only storing values key:value couples. Just like maps, sets provide built-in methods that only return properties defined directly on the object itself:

let options = new Set();

options.evil; // 'polluted';
option.has('evil'); // false
options.has('safe'); // true