Understanding Prototype Pollution in JavaScript Data Models
Learn what prototype pollution is in JavaScript, why it is a security risk, and how to identify and prevent it in your data models.
Prototype pollution is a type of security vulnerability that affects JavaScript applications by allowing unintended modification of an object's prototype. Because in JavaScript almost all objects inherit properties and methods from their prototype, modifying it can cause serious issues like unexpected behavior or security risks throughout your application.
In simple terms, if an attacker can change properties of an object's prototype, they can potentially inject malicious code or cause your program to behave unpredictably. This is especially problematic in applications that handle user input without properly validating or sanitizing it.
Here's an example to help illustrate:
const userInput = JSON.parse('{"__proto__": {"isAdmin": true}}');
const data = {};
// Merging userInput into data
Object.assign(data, userInput);
console.log(data.isAdmin); // undefined
console.log({}.isAdmin); // true - prototype polluted!In the above example, the userInput object contains a special key __proto__. When this is merged into another object (data), it doesn't just add a property to data—it modifies the prototype of all objects. As a result, the isAdmin property is accessible on every object, which should not happen.
How can you protect your data models from prototype pollution?
1. **Avoid directly merging untrusted input**: Never blindly merge user input into your objects using functions like Object.assign or deep merge utilities that don't guard against __proto__ keys. 2. **Validate and sanitize input**: Check for dangerous keys like __proto__, constructor, or prototype and reject or strip them out before using the data. 3. **Use safe merge libraries**: Choose libraries designed to protect against prototype pollution. 4. **Freeze prototypes if possible**: Using Object.freeze on Object.prototype can prevent modification, but this is not always practical.
// Safe merge example with a filter
function safeMerge(target, source) {
for (const key in source) {
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
// Skip dangerous keys
continue;
}
target[key] = source[key];
}
return target;
}
const userInput = JSON.parse('{"__proto__": {"isAdmin": true}, "name": "Alice"}');
const data = {};
safeMerge(data, userInput);
console.log(data.name); // Alice
console.log({}.isAdmin); // undefined, safe!Prototype pollution can cause hard-to-debug errors and potential security breaches, so it's important for JavaScript developers to understand and guard against it in their data models and applications.