JavaScript › Advanced JavaScript

Prototypes and prototype pollution

4 min read Advanced 3 sections

JavaScript inheritance works differently from other languages, through prototypes, and that design enables a uniquely JavaScript vulnerability: prototype pollution. Understanding the prototype chain first makes the bug obvious rather than mysterious.

You'll learn to

  • Explain the prototype chain
  • See how property lookup walks it
  • Understand why pollution cascades across an app

The prototype chain

Every object has a hidden link to a prototype object. When you read a property, JavaScript checks the object, then its prototype, then that prototype’s prototype, up the chain until it finds the property or reaches the end.

const obj = {};
obj.toString;          // exists! — inherited from Object.prototype up the chain

// Almost every object's chain ends at Object.prototype:
//   obj  ->  Object.prototype  ->  null

obj has no toString of its own, but reading it succeeds because lookup walks up to Object.prototype, which nearly every object shares. That shared object is the key to the vulnerability.

How pollution happens

If an attacker can set a property on Object.prototype, that property appears on every object in the application, because they all inherit from it.

// A vulnerable merge/clone that doesn't guard the special key:
function merge(target, source) {
  for (const key in source) {
    if (typeof source[key] === "object")
      merge(target[key], source[key]);
    else
      target[key] = source[key];
  }
}

// Attacker-controlled JSON with a __proto__ key:
const payload = JSON.parse('{"__proto__": {"isAdmin": true}}');
merge({}, payload);

// Now EVERY object appears to have isAdmin:
const user = {};
user.isAdmin;          // true  <- it was never set on user!

The magic key __proto__ refers to the prototype. A merge or clone that copies it without guarding writes onto the shared prototype, and suddenly every object in the app inherits the injected property.

Checkpoint

In prototype pollution, why does setting a property via __proto__ affect objects that the attacker never touched?

Try it yourself

In the console, create an empty object and read a property it never had, like its toString — notice it exists, inherited from the prototype chain. Then reason about why writing to proto would make a new property appear on a different, unrelated object. (Don’t pollute the prototype in a real page — reason it through.)

Key takeaways

  • Property lookup walks the prototype chain up to Object.prototype.
  • proto refers to the shared prototype nearly all objects inherit from.
  • An unguarded merge/clone of attacker data can write to that shared prototype.
  • Polluted properties then appear on every object — leading to XSS or RCE.

Quick quiz

Next, how modern frameworks like React and Angular change the security picture — and where their escape hatches reopen it.

Was this lesson helpful?