Prototype Pollution Security Check (CWE-1321)
What this checks
Protects against prototype pollution in JavaScript/TypeScript where an attacker injects
properties like __proto__ or constructor.prototype through user input, modifying
the prototype chain of all objects. Exploitation leads to property injection, auth
bypass, and remote code execution in some frameworks.
Vulnerable patterns
- Deep merge of user input into a config or options object using a library helper that recurses through
__proto__. Object.assignor spread of a parsed JSON body into a target object — the__proto__key is copied as a regular property and walked by the engine.- Custom recursive merge that iterates source keys with no filter —
__proto__andconstructor.prototypeare merged in alongside everything else. - Dynamic property assignment where both the key and the value come from user input, with no key validation.
Fix immediately
Flag the vulnerable code and explain the risk. Then suggest a fix that establishes these properties. The audited file is JavaScript or TypeScript by definition, so the principles translate directly — apply them using the project's existing utility library and module conventions.
- Any recursive merge, clone, or property copy on user input filters the
dangerous keys —
__proto__,constructor,prototype. The filter runs before assignment, not after; a post-hoc delete does not help because the prototype chain was already mutated. - Dynamic property assignment from user input validates the key against a
blocklist, or sidesteps the issue by using a
Map. AMaphas no prototype-chain exposure; object indexing does. - Config and lookup objects use a null-prototype object when keys come from input. An object created with no prototype cannot be polluted because there is no prototype chain to reach.
- Library deep-merge helpers (
_.merge,_.set,$.extend(true, …)) on untrusted input are replaced with key-filtered wrappers or safe alternatives. The issue is library-version-dependent, so relying on patched versions is fragile; filter at the call site.
When iterating source keys, use the own-keys iterator (e.g. Object.keys),
never the prototype-walking variant.
Verification
- No deep merge, clone, or recursive property copy on user-controlled input proceeds without filtering
__proto__,constructor, andprototypekeys - Dynamic property assignment from user input validates the key against a blocklist or uses
Mapinstead - If a library deep-merge helper is used, it is replaced or wrapped with a key filter before being applied to untrusted input
- Iteration uses an own-keys iterator, not a prototype-walking one