Prototype Pollution

What You Will Learn

  • What JavaScript prototypes are and how the prototype chain works
  • How prototype pollution works as a vulnerability
  • How Object.assign and JSON.parse can be exploited
  • How to identify and prevent prototype pollution

What Is It?

Prototype pollution is a JavaScript vulnerability that enables an attacker to add arbitrary properties to global object prototypes, which may then be inherited by user-defined objects.

Since JavaScript objects inherit from Object.prototype, polluting it affects every object in the application.

Why It Matters

Prototype pollution can lead to:

  • Property injection that bypasses security checks
  • Denial of service (breaking application logic)
  • Remote code execution in Node.js applications
  • XSS when polluted properties reach the DOM

JavaScript Objects

Object Literal

var person = {
    name: "ola",
    home: "lagos"
};

Constructor Function

person = function(name, place) {
    this.name = name;
    this.home = place;
}

person1 = new person("ola", "lagos");

ES6 Class

class Person {
  constructor(name, place) {
    this.name = name;
    this.home = place;
  }

  method() {
    // Method implementation
  }
}

const obj = new Person("ola", "lagos");

Object.create

const person = {
  method() {
    // Method implementation
  }
};

const person1 = Object.create(person);
person1.name = "ola";
person1.home = "lagos";

Function Factory

function createPerson(name, place) {
  return {
    name: name,
    home: place,
    method: function() {
      // Method implementation
    }
  };
}

const person1 = createPerson("ola", "lagos");

The Prototype Chain

Accessing Prototypes

person.prototype.age = 12;

if (person1 instanceof person) console.log(person1.age);

Prototype Chain Lookup

if (person1 instanceof person && person2 instanceof person) {
  console.log(person1.__proto__ === person2.__proto__); // true
}

Prototype Pollution in Practice

Polluting All Object Prototypes

person1.__proto__.__proto__.new = 'polluted';

ola = {};
ola.new === 'polluted'; // true — every object now has this property

Pollution via Object.assign

var input = '{"name":"olamide", "__proto__": {"isAdmin":true}}';

var source = JSON.parse(input);

let vuln = {};

Object.assign(vuln, source);

vuln.isAdmin === true; // true — admin check bypassed!

Server-Side (Node.js) Impact

If an attacker can pollute Object.prototype, properties that do not exist on an object will now return the attacker’s value:

// Before pollution:
let user = {};
user.isAdmin; // undefined

// After prototype pollution:
Object.prototype.isAdmin = true;
user.isAdmin; // true — even though user object was not modified

This can bypass if (user.isAdmin) checks in authentication code.

RCE via Prototype Pollution in Node.js

Some Node.js libraries use polluted properties in ways that lead to code execution, for example through child_process.spawn options that get merged from a polluted prototype.

Prevention

// Use Object.create(null) for dictionaries — no prototype
const safe = Object.create(null);

// Block __proto__ in merge functions
function safeAssign(target, source) {
    for (let key of Object.keys(source)) {
        if (key === '__proto__' || key === 'constructor') continue;
        target[key] = source[key];
    }
}

// Use JSON schema validation on user input
// Use Object.freeze(Object.prototype) in testing

Resources


This site uses Just the Docs, a documentation theme for Jekyll.