highCode Injection

JavaScript Prototype Pollution

What Is This Vulnerability?

Prototype pollution is a vulnerability specific to JavaScript where an attacker can inject properties into Object.prototype or other built-in prototypes. Since all objects in JavaScript inherit from Object.prototype, a polluted property becomes available on every object in the application, potentially altering logic, bypassing security checks, or enabling remote code execution.

Why It Happens

This vulnerability arises when applications use recursive merge, deep clone, or object extension functions that do not guard against keys like __proto__, constructor, or prototype. User-controlled JSON payloads processed by these unsafe functions can modify the prototype chain of all objects in the process.

Example Code

Vulnerablelib/merge.ts
function deepMerge(target: any, source: any) {
  for (const key of Object.keys(source)) {
    if (typeof source[key] === "object" && source[key] !== null) {
      if (!target[key]) target[key] = {};
      deepMerge(target[key], source[key]);
    } else {
      target[key] = source[key];
    }
  }
  return target;
}

app.post("/settings", (req, res) => {
  const userSettings = deepMerge({}, req.body);
  res.json(userSettings);
});
Fixedlib/merge.ts
function deepMerge(target: any, source: any) {
  for (const key of Object.keys(source)) {
    if (key === "__proto__" || key === "constructor" || key === "prototype") {
      continue;
    }
    if (typeof source[key] === "object" && source[key] !== null) {
      if (!target[key]) target[key] = {};
      deepMerge(target[key], source[key]);
    } else {
      target[key] = source[key];
    }
  }
  return target;
}

app.post("/settings", (req, res) => {
  const userSettings = deepMerge(Object.create(null), req.body);
  res.json(userSettings);
});

How Hackers Exploit It

An attacker sends a JSON payload like {"__proto__": {"isAdmin": true}}. If the server uses an unsafe merge function, Object.prototype.isAdmin is set to true. Every subsequent object in the application that checks obj.isAdmin will find it to be true, potentially granting admin access. In some cases, prototype pollution chains with template engines or child_process can lead to remote code execution.

How to Fix It

Use Object.create(null) for lookup maps to avoid prototype inheritance. In merge and clone functions, skip keys named __proto__, constructor, and prototype. Prefer well-maintained libraries like lodash (which patched this in v4.17.12+) over custom deep-merge implementations. Freeze Object.prototype in test environments to detect pollution. Use Map instead of plain objects for user-controlled key-value stores.

Frequently Asked Questions

What is prototype pollution in simple terms?
In JavaScript, all objects share a base template called Object.prototype. Prototype pollution lets an attacker add properties to this template. Once polluted, every object in the application inherits the injected property, which can change application behavior or bypass security checks.
Can prototype pollution lead to remote code execution?
Yes. When combined with certain template engines (like EJS or Pug) or child_process functions, prototype pollution can be chained to achieve full remote code execution. The attacker pollutes properties that these libraries read during execution.
How do I detect prototype pollution in my codebase?
Use static analysis tools like ESLint plugins that flag unsafe property assignment patterns. Run automated security scanners like Snyk or npm audit. In tests, freeze Object.prototype and check for unexpected modifications after processing untrusted input.

Related Security Topics

Check Your Code for This Vulnerability

Run a free scan to check if your site is affected by javascript prototype pollution.