Prototype Pollution
Prototype pollution writes to JavaScript object prototypes through unsafe merges and path assignments, silently altering behavior of every object and enabling injected logic or auth bypass.
Definition
Prototype pollution modifies Object.prototype — or a constructor prototype — via keys like __proto__, constructor, or prototype in recursive merge, clone, or set-by-path utilities. Once polluted, all objects inherit the injected properties: a crafted isAdmin property can flip checks; gadget code can escalate to XSS or RCE. Node and browser code are both affected.
Context and scope
Found in deep-merge of user-controlled JSON, query-string parsers, dot-path assignment helpers, and template engines. The follow-up gadgets determine impact from denial of service to code execution.
Common misconceptions
- Freezing Object.prototype ends it — real libraries pollute via constructor.prototype chains that a shallow freeze misses
- Only deep merges are vulnerable — path setters, query parsers, and destructuring defaults have all shipped the bug
- Server-side Node is safe because no DOM — gadget chains exist server-side too: template engines and child process option injection
Anti-patterns
- Recursively merging user JSON into configuration objects without key filtering
- Building set-by-path helpers that accept constructor and __proto__ as segments
- Upgrading dependencies piecemeal and missing that a transitive merge utility remained unpatched
Related concepts
Related examples
Authoritative source
What it is
JavaScript property lookup walks the prototype chain. If attacker input can write onto a shared prototype, every object later in the process inherits that property. Security checks reading a boolean off any object suddenly see attacker values.
How it works
Pollution entry points are utilities that treat input keys as paths into object graphs: deep merge of two JSON documents, a query-string library expanding a[b][proto][x], or a set(obj, user.path, value) helper. The dangerous keys are proto, constructor, and prototype appearing anywhere along the path. Gadget exploitation then finds code that reads the polluted property in a security-relevant way.
When to audit
Anywhere untrusted JSON deep-merges into defaults, query strings deserialize into objects, and file or state paths come from users. Prefer structured cloning and explicit field copying over generic deep merge of mixed-trust data.
Pitfalls
Patches ship per library, so dependency trees need re-auditing after every change. Null-prototype objects help but do not fix merge utilities that still write through constructor chains. Dynamic gadget discovery means severity depends on what the app does with inherited properties — assess code, not just the sink.