Prototype pollution lets an attacker change properties on shared JavaScript objects, which can affect every object in the application. OWASP's defenses are to use Map or Set for keyed data, create plain objects with a null prototype, and freeze built-in prototypes. Each has limits, so combine them with careful handling of untrusted keys.
What it is
OWASP describes prototype pollution as a critical vulnerability that can let attackers manipulate an application's JavaScript objects, with outcomes ranging from unauthorized data access and privilege escalation to remote code execution.
In JavaScript, objects inherit from a prototype. If code lets an attacker set a property on that shared prototype, for example through keys like __proto__ in merged or copied data, objects created later can appear to have properties that the attacker chose. Code that checks a flag on an object may then read the attacker's value.
Defense 1: use Map or Set
For keyed data that comes from users, use new Map() or new Set() instead of object literals. A Map keeps entries separate from the prototype chain, so a key named __proto__ is just a key.
Defense 2: null prototype objects
If you need a plain object, create it with Object.create(null) so it does not inherit from Object.prototype. OWASP also lists an object literal whose __proto__ key is set to null as a last resort option.
const settings = Object.create(null);
settings[userKey] = userValue;
Defense 3: freeze built-in prototypes
Object.freeze() on built-in prototypes stops new properties being added and makes existing data properties non-writable. OWASP adds two cautions. Freezing is shallow, so objects referenced by those properties stay mutable unless frozen separately. And you must test compatibility first, because libraries that modify built-in prototypes can break.
Do not rely on seal
Object.seal() blocks adding and removing properties and changing their configuration, but existing writable values can still change. OWASP says not to rely on sealing for this.
The Node.js flag
Node can run with --disable-proto=delete, which removes the __proto__ property. OWASP labels this defense in depth and notes that pollution is still possible through constructor.prototype.
node --disable-proto=delete app.js
What the OWASP page does not cover
The OWASP page does not discuss how pollution arises in merge or clone helpers, or schema validation. Those are common mitigations elsewhere, such as rejecting __proto__, constructor and prototype as keys when merging, and validating input shape. Treat that as a point to verify against your own libraries, not as OWASP guidance.
Where the risk lives in practice
Often not in your own code but in a dependency that deep merges objects, parses query strings into nested objects, or sets values by path. Keep an inventory of such libraries and update them. Reachability analysis helps here, because it shows whether the vulnerable function in a dependency is actually called by your code. Safeguard offers reachability analysis for this purpose.
Click through it at your own pace, or open it full screen.
A short checklist
- Replace user keyed object literals with Map where practical.
- Create dictionary style objects with a null prototype.
- Test freezing built-in prototypes in staging.
- Update libraries that merge or clone objects.
- Add a test that sends a body with a
__proto__key and confirms normal objects are unaffected.
Quick check
Does the Node flag fix prototype pollution completely?
No. OWASP calls it defense in depth, and pollution through constructor.prototype remains possible.
Sources
Last reviewed: 19 October 2026.