Prototype Pollution

Prototype pollution lets an attacker set properties on Object.prototype, contaminating every plain object the program uses.

Definition

Prototype pollution is a JavaScript-specific vulnerability in which an attacker writes a property onto `Object.prototype` (or another shared prototype). Because every plain object in JavaScript inherits from that prototype, the polluted property becomes visible everywhere in the program — including in security-sensitive branches that check for a property's existence without `hasOwnProperty`.

The bug class came to prominence in 2018 with widespread exploitation against lodash, jQuery, and dozens of popular npm packages. The pattern is so easy to introduce that recursive `merge` / `set` / `extend` utility functions across the ecosystem have all been audited and patched at least once.

How it works

The application has a function that merges a user-controlled object into a target object recursively. The user supplies an object with the special key `__proto__` (or `constructor.prototype`). The recursive merge walks into that property, treating it as a normal object — but it is the global `Object.prototype`. Any property the attacker sets there becomes visible to every plain object in the program.

Exploitation depends on what code path the polluted property reaches. Common second-stage gadgets: `isAdmin` becomes true everywhere, an authorisation flag flips, a template engine's `escape` flag is forced off, an option object's `shell` becomes true and a subsequent `child_process` call spawns a shell.

Impact

Privilege escalation, authorisation bypass, denial of service (override prototype methods like `toString` to throw), and — in the worst chains — remote code execution when the polluted property reaches a sink that interprets it as configuration.

Mitigation

Use `Object.create(null)` for any object that will accept attacker-controlled keys. Reject `__proto__` / `constructor` / `prototype` keys at the JSON parse boundary or in the merge utility. Use `Map` instead of plain objects when keys can be arbitrary. Freeze `Object.prototype` at process start in defence-in-depth deployments.

Examples

  • CVE-2019-10744 — Prototype pollution in lodash's defaultsDeep.
  • CVE-2022-21824 — Prototype pollution in Node.js console class.

See also

References