Skip to Content

Prototype Pollution in JavaScript: How It Works and How to Prevent It

How one unsafe merge function can make every object in your app an admin, and the practices that stop it
January 4, 2026 by
Prototype Pollution in JavaScript: How It Works and How to Prevent It
Ibrahim Zakaria


JavaScript security in the real world

JavaScript runs websites, dashboards, mobile apps and a good share of back-end systems. If you build software today, you almost certainly ship JavaScript.

Most developers learn how to make JavaScript work, and far fewer learn how to make it secure. University courses in Beirut and across Lebanon tend to focus on syntax, basic logic and small projects, and real-world JavaScript security risks rarely make it into the syllabus.

A good example is prototype pollution, a vulnerability many developers have never heard of that can still break an application completely.

This article explains prototype pollution in plain terms, shows why it is dangerous, and lists the JavaScript security practices that protect your application against it.

JavaScript prototypes in simple terms

JavaScript works differently from many other languages.
Instead of classical inheritance, it uses prototypes.

Every JavaScript object can inherit properties from another object, called its prototype. When you read a property:

  1. JavaScript checks the object itself
  2. If the property is not there, it checks the prototype
  3. This continues up the chain until it reaches Object.prototype

The design is flexible, and it carries a risk.
If someone manages to change Object.prototype, the change reaches every object in your application.
That is where prototype pollution comes in.

What is prototype pollution?

Prototype pollution happens when an attacker manages to add properties to Object.prototype, usually through data your application accepts from outside.

When this happens:

  • Every object in your application may inherit the attacker's values
  • Security checks can fail without any error
  • Business logic can be bypassed quietly

Because nothing crashes, this kind of vulnerability is hard to notice and even harder to debug.

A real example: unsafe object merging

Many JavaScript applications merge user input into default configuration objects.

A simple recursive merge function might look like this:

function merge(target, source) {
  for (let key in source) {
    if (typeof target[key] === 'object' && target[key] !== null) {
      merge(target[key], source[key]);
    } else {
      target[key] = source[key];
    }
  }
}

Now imagine an attacker sends this JSON body:

{
  "__proto__": {
    "isAdmin": true
  }
}

JSON.parse turns "__proto__" into an ordinary key, so the loop visits it. But target["__proto__"] is Object.prototype itself, so the merge writes isAdmin into the prototype that every object shares.

From then on, every object in the process has:

({}).isAdmin === true

Why this is a serious security risk

Once the prototype is polluted, the impact can be severe:

  • Authentication bypass
    If your code checks permissions with if (user.isAdmin), and user has no isAdmin property of its own, attackers may get admin access.
  • Unexpected behavior
    Logic breaks in ways that are difficult to trace.
  • Crashes or denial of service
    Properties your code relies on can be overwritten.

These attacks have been found in real production systems and in widely used libraries.

JavaScript security practices that prevent prototype pollution

1. Never trust user input

Validate incoming data against a schema, and reject objects that contain dangerous keys such as __proto__, constructor or prototype. Check the object's own keys; a check like obj.__proto__ looks at the inherited prototype and is true for every normal object.

const BLOCKED = new Set(["__proto__", "constructor", "prototype"]);

function sanitize(obj) {
  for (const key of Object.keys(obj)) {
    if (BLOCKED.has(key)) {
      throw new Error("Prototype pollution attempt: " + key);
    }
    const value = obj[key];
    if (typeof value === "object" && value !== null) {
      sanitize(value);
    }
  }
}

The same rule belongs in your merge function: skip blocked keys, and only follow keys that are the object's own (Object.hasOwn(source, key)).

2. Use Object.create(null) or Map for dictionaries

Objects created with Object.create(null) do not inherit from Object.prototype.

const safeObject = Object.create(null);
safeObject.key = "value";

For data keyed by user-supplied strings, a Map avoids the problem altogether. Both techniques remove whole classes of attacks.

3. Be careful with libraries

Popular libraries have shipped prototype pollution bugs too; deep-merge helpers such as lodash.merge were patched for exactly this.

If you use them:

  • Keep them updated and watch security advisories (npm audit helps)
  • Sanitize inputs before merging
  • Follow the library's documented security guidance

4. Freeze prototypes (with caution)

Object.freeze(Object.prototype);

This stops any change to the prototype, but it may break libraries that extend it. Test well before turning it on in production. In Node.js, the --disable-proto=delete flag removes the __proto__ accessor altogether.

Why many developers never meet this at university

Academic programs usually cover syntax, exams and small projects. Production software also needs security thinking, an understanding of how attacks work, defensive coding habits and the practices the industry has learned the hard way. Prototype pollution sits in that gap, and so do many of the issues we find when we review real codebases.

Checking your own code

Prototype pollution is one example among many. Code generated with AI tools makes these issues more common, because a merge helper or a config loader is exactly the kind of code an assistant writes quickly and nobody reviews. Our AI code assessment checks an application, whoever or whatever wrote it, for security, best practices, maintainability and production readiness, and documents each finding with the steps to reproduce it. If you are building a new product, our custom software team writes code with these checks in place from the start.

If you are unsure whether your application is exposed, book a free 30-minute call and tell us about your stack.

Prototype Pollution in JavaScript: How It Works and How to Prevent It
Ibrahim Zakaria January 4, 2026
Share this post
WhatsApp usAI agent replies 24/7
Book a free 30-minute call