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=trueto gain administrative access across the entire application - Authorization Bypass: If an API checks
user.roleagainst a whitelist, polluting the prototype can add arbitrary roles that pass validation - Denial of Service: Prototype pollution can break
Object.hasOwnPropertychecks, 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__orconstructor.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.mergev4.6.0+ includes prototype pollution protectionmerge-optionsv3.0.0+ is safe by defaultwebpackv5+ 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.