skip to content
Back to
Home Bounties Research Advisories CodeQL Wall of Fame Get Involved Events
January 26, 2021

GHSL-2020-160: Prototype pollution in Merge-deep

GitHub Security Lab

Coordinated Disclosure Timeline


Merge-deep actively attempts to prevent prototype pollution by blocking object property merges into __proto__, however it still allows for prototype pollution of Object.prototype via a constructor payload.


merge-deep 3.0.2 (latest version)

Tested Version



merge-deep can be tricked into overwriting properties of Object.prototype or adding new properties to it. These properties are then inherited by every object in the program.

Here is an example, in which we assume that payload is provided by an attacker, and isAdmin is a property that is later on used to check whether a user is authorized to perform some sensitive operation:

var mergeDeep = require("merge-deep");
var payload = '{"constructor": {"prototype": {"isAdmin": true}}}';
mergeDeep({}, JSON.parse(payload));

After this code has run, Object.prototype.isAdmin is true. But Object.prototype is on the prototype chain of most objects, so we also have {}.isAdmin == true, and indeed u.isAdmin == true for most other objects u, including, perhaps, objects used to represent users.

It is important to note that the above code snippet throws an exception (since Object.prototype cannot be reassigned), but it still sets the property (since it can be mutated). In some settings this might make the vulnerability difficult to exploit, but in others (for example web servers, which generally are written to be tolerant to route-handler crashes) it will still be easily exploitable.


JavaScript prototype pollution can lead to a variety of application context specific impacts ranging from Denial of Service (DoS) to Remote Code Execution (RCE).


This issue was discovered and reported by GitHub team member @max-schaefer.


You can contact the GHSL team at, please include GHSL-2020-160 in any communication regarding this issue.