January 26, 2021

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

GitHub Security Lab Team

Coordinated Disclosure Timeline

  • 09/30/2020: maintainer notified
  • 01/04/2021: disclosure deadline, no maintainer response
  • 01/04/2021: created issue on project as final attempt to notify maintainer
  • 01/05/2021: maintainer acknowledges report and is working on a patch
  • 01/13/2021: version 3.03 released to npm


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 securitylab@github.com, please include GHSL-2020-160 in any communication regarding this issue.