HIGH Authentication & Authorization

Prototype Pollution in APIs

What is Prototype Pollution?

Prototype Pollution is a critical JavaScript vulnerability that occurs when an attacker can modify an object's prototype, which is the template from which all objects inherit properties. In Node.js and JavaScript applications, objects inherit from Object.prototype by default. When user-controlled data is merged into an object without proper sanitization, attackers can inject properties into the prototype chain.

The vulnerability typically manifests through unsafe object merging operations. Consider this vulnerable pattern:

const merge = require('lodash.merge');
const user = JSON.parse(req.body);
const config = merge({}, user); // Vulnerable: user can pollute Object.prototype

If an attacker sends a request with __proto__.admin=true, this property gets added to Object.prototype, affecting all objects in the application. The pollution spreads because every object inherits from the prototype, creating a single point of failure that can compromise the entire application.

How Prototype Pollution Affects APIs

In API contexts, Prototype Pollution enables attackers to escalate privileges, bypass authorization checks, and manipulate application logic. The attack surface expands significantly because APIs often merge user input with internal objects.

Common attack scenarios include:

  • Privilege Escalation: An attacker adds __proto__.isAdmin=true to gain administrative access across the entire application
  • Authorization Bypass: If an API checks user.role against a whitelist, polluting the prototype can add arbitrary roles that pass validation
  • Denial of Service: Prototype pollution can break Object.hasOwnProperty checks, causing infinite loops or crashes
  • Data Exfiltration: Attackers can add getter properties that execute code when accessed, potentially leaking sensitive data

Consider an API that merges user preferences with default settings:

const defaults = { theme: 'light', notifications: true };
const userPrefs = JSON.parse(req.body);
const settings = { ...defaults, ...userPrefs }; // Vulnerable to prototype pollution

An attacker could send __proto__.toString=console.log, causing unexpected behavior when objects are stringified throughout the application.

How to Detect Prototype Pollution

Detecting Prototype Pollution requires both static code analysis and runtime testing. Look for these red flags in your codebase:

Code Patterns to Flag:

  • Unsafe use of Object.assign(), lodash.merge(), or spread operators with user input
  • Direct assignment to __proto__ or constructor.prototype
  • Dynamic property access using bracket notation with user-controlled keys

Runtime Testing:

Test your API endpoints by sending requests with prototype pollution payloads:

{
  "__proto__": {
    "isAdmin": true,
    "admin": true,
    "role": "admin"
  }
}

Verify that these properties don't persist or affect application behavior. Use tools like console.log(Object.prototype) before and after requests to detect pollution.

middleBrick Detection: middleBrick's black-box scanning automatically tests for Prototype Pollution by sending crafted payloads to API endpoints and analyzing responses for signs of prototype manipulation. The scanner checks for unsafe object merging patterns and verifies that user input cannot modify object prototypes. This takes 5-15 seconds and requires no credentials or configuration—just submit your API URL to get a security score with detailed findings.

Prevention & Remediation

Preventing Prototype Pollution requires a defense-in-depth approach. Here are concrete fixes for common vulnerable patterns:

Safe Object Merging:

// Vulnerable
const unsafeMerge = (target, source) => Object.assign(target, source);

// Secure - use a safe merge function
const safeMerge = (target, source) => {
  const result = { ...target };
  for (const [key, value] of Object.entries(source)) {
    if (key.startsWith('__proto__') || key === 'constructor') {
      continue; // Block prototype pollution
    }
    result[key] = value;
  }
  return result;
};

Input Sanitization:

const sanitizeInput = (input) => {
  if (typeof input !== 'object' || input === null) return input;
  
  const sanitized = {};
  for (const [key, value] of Object.entries(input)) {
    if (key.startsWith('__proto__') || key === 'constructor') {
      continue;
    }
    sanitized[key] = sanitizeInput(value); // Recursively sanitize
  }
  return sanitized;
};

Library Updates: Many vulnerable libraries have been patched. Update to versions that include prototype pollution protections:

  • lodash.merge v4.6.0+ includes prototype pollution protection
  • merge-options v3.0.0+ is safe by default
  • webpack v5+ includes prototype pollution mitigations

Runtime Protection: Implement runtime checks to detect pollution attempts:

const originalHasOwnProperty = Object.prototype.hasOwnProperty;
Object.defineProperty(Object.prototype, 'hasOwnProperty', {
  value: function(key) {
    if (key.startsWith('__proto__') || key === 'constructor') {
      throw new Error('Prototype pollution attempt detected');
    }
    return originalHasOwnProperty.call(this, key);
  },
  configurable: true
});

Real-World Impact

Prototype Pollution has caused significant security incidents in production systems. In 2018, the popular lodash library was found vulnerable to prototype pollution, affecting thousands of applications. The vulnerability (CVE-2018-16487) allowed attackers to modify Object.prototype through unsafe merging operations.

A notable real-world example involved a Node.js application where an attacker exploited prototype pollution to escalate privileges. By sending __proto__.isAdmin=true in a request, they gained administrative access to the entire system. The application used unsafe merging to combine user preferences with default settings, creating the perfect attack vector.

In 2021, a high-severity vulnerability in the node-forge library (CVE-2021-32631) allowed prototype pollution through certificate parsing. Attackers could craft malicious certificates that, when parsed, would pollute the prototype chain and potentially execute arbitrary code.

The financial impact of Prototype Pollution incidents can be severe. A single vulnerability can lead to complete account takeover, data breaches, and compliance violations. Organizations often discover these vulnerabilities only after a breach occurs, making proactive scanning essential for API security.

Frequently Asked Questions

Can Prototype Pollution affect non-JavaScript APIs?
Prototype Pollution is specific to JavaScript and environments that use JavaScript objects. However, similar concepts exist in other languages. For example, Python's class attributes and Ruby's singleton classes can be manipulated in analogous ways. The key difference is that JavaScript's prototype chain and dynamic nature make it particularly susceptible to this type of attack.
How does middleBrick detect Prototype Pollution in APIs?
middleBrick's black-box scanner automatically tests API endpoints for Prototype Pollution by sending crafted payloads that attempt to modify object prototypes. The scanner analyzes responses to detect if user input can affect prototype properties. This takes 5-15 seconds with no setup required—just submit your API URL. middleBrick also checks OpenAPI specifications for unsafe object merging patterns and provides remediation guidance if vulnerabilities are found.
Is Prototype Pollution still relevant if I'm using TypeScript?
Yes, Prototype Pollution affects TypeScript applications at runtime, even though TypeScript provides compile-time type checking. The vulnerability occurs when JavaScript code executes, regardless of whether it was written in TypeScript or JavaScript. TypeScript's type system cannot prevent prototype pollution because it's a runtime issue. You still need to follow the same prevention practices and use safe merging functions.