on the vulnerability of Prototype Pollution

on the vulnerability of Prototype Pollution

Prototype Pollution (CVE-2023-45811, CVE-2023-38894, CVE-2019-10744) is not a new breach, you have probably already read about it on Habre, PortSwigger, and even in scientific journals, but there is a nuance. Despite the large number of publications, some popular solutions still remain vulnerable to it. The next patient is a TypeScript library @clickbar/dot-diver. The CVE-2023-45827 vulnerability is fixed in version 1.0.2 and above, so we will calmly tell you what could have happened to your product, but fortunately did not.

Below, read about how the library had to be used to encounter the Prototype Pollution vulnerability. By the way, we wrote about it in our Telegram channel POSIdev – there are fresh news about secure development, AppSec, as well as regular reviews of trending threats and our favorite “Friday memes” column.

So let’s go!

A little about Prototype Pollution

In JavaScript, all entities are objects, including functions and class definitions. The process of imitation is implemented through the model of prototypes. Each JavaScript object is associated with a special object called a prototype. The object inherits all the properties of the associated prototype. An embedded field is used to access the object’s prototype __proto__. The search for any field in the object is carried out along the prototype chain: first this field is searched for in the object, then in the prototype, and so on – up to the highest level of inheritance.

Prototype Pollution allows the attacker “contaminate” the field of the global objectwhich can be inherited by user objects and create a threat to the security of the program.

The main conditions for the successful implementation of a Prototype Pollution attack:

  1. Untrusted input data used to pollute a global object (prototype pollution source).

  2. The presence of vulnerable functions that can lead to code security problems (sink).

  3. The possibility of using a “contaminated” field of a global object without filtering it in a vulnerable function (exploitable gadget).

The attack implementation mechanism looks like this:

  1. An attacker “pollutes” a property of a global object through an accessible object.

  2. The program uses an object that inherits from the “tainted” global object for the vulnerable function.

  3. The vulnerable function uses a field from a “tainted” global object specified by the attacker, resulting in a security breach.

Main fields used in attacks:

Vulnerability in dot-diver

Library @clickbar/dot-diverwritten in TypeScript (source code), provides a convenient API for reading the value of a field from an object (using the function getByPath) and writing the value in the object field (using the function setByPath).

A vulnerability was discovered in the function setByPathwhich takes three arguments:

  • object – An object whose property is set to a value,

  • path — path pattern to the property to be changed,

  • value — the value that will be in the field in the specified way.

When using the function setByPath there is a recursive enumeration of the fields in the path template. If the required field is found, the required value is assigned to it.

An example of using the function setByPath:

The main problem with using this function is that if the path value contains a path to the prototype, it becomes possible to set the properties of the prototype, which can lead to pollution of the global object.

Function code before patching (version 1.0.1):

This code after patching (version 1.0.2):

In the patch, a check for the presence of an own field in the object was added (using the function Object.prototype.hasOwnProperty) before its change. If the field is missing, an exception is thrown with a corresponding message.

An example of operation

As an example, an application for accounting for books read is used, in which a mechanism for distinguishing users with different roles is implemented:

  • user — with the right to enter data on books read and the possibility of viewing;

  • admin – With the right to remove books from the list.

Access delimitation is implemented using an additional field isAdmin, which is just a user object with a successful credential validation result for the admin role. Other users do not have this field.

A code fragment that handles a request to delete books by key title and implements control of access rights.

The program uses the following API commands:

$curl -v -X GET -H

$curl -v -X PUT -H "Content-Type:application/json" --data '{"auth":{"name":"reader", "pwd":"books"},"title":"Tom Sawyer"}'

$curl -v -X DELETE -H "Content-Type:application/json" --data '{"auth":{"name":"reader", "pwd":"books"},"title":"Tom Sawyer"}'

After attempting to remove a book from the list on behalf of the user reader a response with a code is returned 403 and message text Access deniedwhich signals the lack of rights to perform such actions.

An attack payload is added to the request:

$curl -v -X PUT -H "Content-Type:application/json" --data '{"auth":{"name":"reader", "pwd":"books"},"title":"Tom Sawyer", "note":"__proto__.isAdmin", "text":true}'

In response to the request, the successful result of updating the book list is displayed. In addition, in the global object Object a field appeared isAdmin.

After re-requesting the book to be removed from the list on behalf of the user reader in the response, a message is returned about the deletion of the book, which signals the successful implementation of the attack and the bypassing of the access delimitation mechanism implemented in the application.


Basic recommendations for the elimination of security problems related to the vulnerability of Prototype Pollution:

  • constant update of packages to the latest stable versions;

  • search for vulnerable components using SCA and SAST;

  • processing of untrusted user data at the program entrance;

  • the use of constructors in the absence of the need to imitate objects:

    • let obj = Object.create(null),

    • let obj = {__proto__:null};

  • API functions can be used to protect global prototypes from being modified: Object.freeze() and Object.seal(). But it should be taken into account that they can disrupt the operation of libraries that use the mechanism for changing attributes in global prototypes.

Oleksandr Boldyrev

The leading specialist of the expert group of static analysis of applications

Additional materials

CVE card



CVSS 3.1





Prototype Pollution


Depends on the further use of the object’s properties to implement critical functions (segregation of rights, code execution, business logic)

Description package

A library in TypeScript @clickbar/dot-diver up to and including version 1.0.1 that provides a convenient API for reading the value of a field from an object (function getByPath) and writing the value in the object field (function setByPath)

Related posts