By Daniel Elkabes, Vulnerability Research Team Leader at WhiteSource
Prototype Pollution is one of the less known vulnerabilities in the security community. Researchers started to discuss it as a potential attack vector around 2017, and the first vulnerabilities were found in the wild at the start of 2018.
In this article, we’re going to take a deep dive into what Prototype Pollution vulnerabilities are, and how they can be mitigated.
An Objects Prototype may also have a Prototype, and from it, it can inherit his Prototype or other attributes, and so on. This is referred to as a prototype chain.
There are three main points we need to know about__proto__ :
The animation shows the Objects with their Prototypes, then a new Prototype (Prototype_#4) is added on the _proto_ of another Object (Object_#3). This causes all of the Objects, including their prototypes (as they are objects too), to inherit the new Prototype — Prototype_#4. The result: the application crashes.
Let’s take a look at one of the Prototype Pollution vulnerabilities detected by the WhiteSource security research team.
set()function in the “getobject” package intends to assign properties to an Object, it accepts three arguments Obj, parts and value. Because there is no validation, the values passed into parts and value arguments can be manipulated by an attacker that can supply a malicious value by adjusting parts to include__proto__. Next, check will be assigned to__proto__ with the value “polluted”, polluting all the Objects in our application.
In the output, we can see that before the pollution occurs, obj2 .check was undefined, then, when running the set() function with our arguments(obj, “__proto__.check“, “polluted”), the pollution occurs. Now obj2 .check exists, and its value is “polluted”. By assigning a new “unknown” Prototype to all the Object in the application we are causing a Denial of Service for the whole application.
Now that we know where Prototype Pollution came from and how Prototype Pollution vulnerabilities work, let’s take a look at the data.
Our research team dove into the WhiteSource open source vulnerabilities database to learn how the community has been addressing Prototype Pollution vulnerabilities over the past few years.
In the graph above we see how many Prototype Pollution vulnerabilities have been published each year since the security community became aware of them. Looking back, there is a huge upward trend in 2019 and especially in 2020. It’s still early to say how many Prototype Pollution vulnerabilities will be published in 2021, currently it seems that maybe the upward trend will stabilize.
The pie chart above displays WhiteSource’s contribution to the security effort of detecting Prototype Pollution vulnerabilities. WS IDs are vulnerabilities that were published on the npm advisory and haven’t been published on the NVD. “CVE by WhiteSource” refers to vulnerabilities published on the NVD after being detected and reported by our security research team since WhiteSource became a CNA (CVE numbering authority).
As you can see, many Prototype Pollution vulnerabilities detected in open source components are reported within the community, but are yet to be added to the NVD. This is another example of how open source vulnerabilities can often be found outside of the NVD. While the open source community works hard to detect, fix, and report on security issues, due to the decentralized nature of the community, issues are often published on community issue trackers and advisories. That’s one of the reasons WhiteSource joined the CNA community, to help support the open source community and ensure that security issues are published across all platforms.
__proto__ might have been a useful feature in the past, but, since it was standardized to ensure compatibility with web browsers, the feature is no longer recommended by most in the community. It’s yet to be determined whether it will be removed or kept for compatibility purposes. The popular suggestion is to avoid using this functionality — MDN goes as far as referring to it as deprecated and recommends usingObject.getPrototypeof. Considering today’s best practices, it’s hard to say that __proto__ is anything other than a vulnerability.
This situation leaves maintainers and developers with the peculiar added task of securing their code from a feature of the coding language they are using.
There are a number of ways to mitigate Prototype Pollution vulnerabilities:
– Object.freeze will mitigate almost all cases. Freezing an Object prevents new Prototypes from being added to it.
– Using schema validation to ensure that the JSON data contains the expected attributes. This will remove __proto__ if it appears in the JSON.
– Using map primitive, which was introduced in the EcmaScript 6 standard, and is now well-supported in the NodeJS environment.
– Objects created using the Object.create(null) function won’t have the__proto__ attribute.
– In general, pay attention when using recursive merge functions, since they are more prone to Prototype Pollution vulnerabilities than other functions.
It’s safe to say that new Prototype Pollution vulnerabilities will continue to be detected in the years to come. As we mentioned, it’s still unclear if or when__proto__ might be removed in the future. Until then, we as a community can do our best to develop our code with this security vulnerability in mind, and mitigate the cases that already exist.