Skip to content

Prototype pollution

Prototype pollution is a vulnerability where an attacker is able to inject properties into the top level JavaScript prototype. This basically adds an attacker defined property to all JavaScript objects. While this might seem unimportant, the impacts of this are quite severe.

What is prototype pollution?

In JavaScripts, inheritance is implemented via prototypes. Each object has a __proto__ property that is another object. The object inherits all properties in its __proto__. In JS, almost all objects are subclasses of Object, thus share its prototype. This means that if we set a value on a.__proto__ it will most likely affect other objects as well. Here's an example:

js
a = {name: "jro"}
b = {name: "sus"}
b.__proto__.sus = "yes"
console.log(a.sus)
// => yes

However, prototype pollution is unable to overwrite existing properties:

js
a = {name: "jro", sus:"no"}
b = {name: "sus"}
b.__proto__.sus = "yes"
console.log(a.sus)
// => no

Impacts of prototype pollution

While prototype pollution might be viewed as a low severity vulnerability, the right conditions can enable prototype pollution to have severe impacts.

Authentication bypass

Consider this code:

js
a = {name: "jro"}
b = {name: "sus"}
b.__proto__.admin = true
console.log(a.admin)
// true

Prototype pollution can also occur on the client side

RCE

When prototype pollution occurs in server side code and a templating engine is used, an attacker is often able to set internal properties in the templating engine, resulting in RCE.

See gunship.

Identifying prototype pollution

Libraries such as certain versions of lodash and the flat library perform unsafe object unpacking that enable prototype pollution. Suspiciously written code that assigns arbitrary values to arbitrary properties could be indicative of prototype pollution.