flawopen.com/Vulnerabilities/JavaScript Prototype Pollution

JavaScript Prototype Pollution

High Severity CWE-1321 Supply Chain & Runtime
ELI5 — The Master DNA Stamp

Imagine a factory that manufactures toy robots. Every robot inherits its default settings (e.g. 'Can this robot fire lasers? No') from a single master blueprint in the supervisor's office. A sneaky visitor writes on the master blueprint: 'Can this robot fire lasers? YES'. Suddenly, every single robot built in the factory—past, present, and future—inherits the ability to fire lasers! In JavaScript Prototype Pollution, an attacker modifies Object.prototype, altering default properties across every single object in the entire Node.js server.

Target: Node.js backends, recursive object merge/clone functions (lodash, jQuery)
Vector: JSON payloads containing __proto__, constructor.prototype
Impact: Authentication bypass (injecting isAdmin: true), Remote Code Execution
Remediation: Input key filtering, Object.create(null), Map data structures

The Mechanism & Root Cause

JavaScript objects inherit properties from prototype objects via the prototype chain. When an application recursively copies untrusted user objects into existing configurations without filtering property keys, an attacker supplies properties named __proto__ or constructor.prototype. The recursive assignment mutates the base Object.prototype, causing all newly created objects to inherit the attacker's values.

utils.js (Vulnerable Recursive Merge)Vulnerable
// VULNERABLE: Recursive merge without prototype key filtering
function merge(target, source) {
    for (let key in source) {
        if (typeof source[key] === 'object' && source[key] !== null) {
            if (!target[key]) target[key] = {};
            merge(target[key], source[key]); // Recursively copies __proto__!
        } else {
            target[key] = source[key];
        }
    }
    return target;
}
// Attacker sends: JSON.parse('{"__proto__": {"isAdmin": true}}')
utils.js (Hardened Safe Merge)Hardened
// HARDENED: Disallow dangerous prototype chain keys
function mergeSafe(target, source) {
    const BLOCKED_KEYS = ['__proto__', 'constructor', 'prototype'];

    for (let key of Object.keys(source)) {
        if (BLOCKED_KEYS.includes(key)) {
            continue; // Strictly discard prototype mutation attempts
        }
        if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
            if (!target[key]) target[key] = {};
            mergeSafe(target[key], source[key]);
        } else {
            target[key] = source[key];
        }
    }
    return target;
}

The Attack & Exploit Sequence

Defensive Engineering & Prevention Rules

Explore related security topics and post-mortems: Complete Security Directory →