Vulnerability

Prototype Pollution
detect, understand, remediate

Prototype pollution lets attackers inject properties into JavaScript Object prototypes through unsafe merge or clone operations, potentially leading to XSS, RCE, or denial of service.

No credit card required. Free plan available forever.

Severity

High

CWE ID

CWE-1321

OWASP Top 10

A06:2021 – Vulnerable and Outdated Components

CVSS 3.1 Score

8.6

What is prototype pollution?

Prototype pollution is a JavaScript-specific vulnerability, classified under CWE-1321, that allows an attacker to inject properties into JavaScript object prototypes. Since nearly every object in JavaScript inherits from Object.prototype, polluting it means that the injected properties become available on all objects throughout the application. This can lead to denial of service, property injection, and in severe cases, cross-site scripting or remote code execution.

The vulnerability arises when applications use recursive merge, deep clone, or property assignment functions that do not filter special keys like __proto__, constructor, and prototype. Attackers exploit these by submitting crafted JSON payloads through API requests, query parameters, or form data. Libraries like older versions of lodash, jQuery extend, and Hoek have historically been vulnerable, making this issue closely related to vulnerable dependency management.

Prototype pollution is particularly insidious because the polluted property does not affect the source object alone. It propagates globally, meaning that a single malicious request can alter the behavior of every subsequent operation in the application process. This makes exploitation difficult to trace and can cause cascading failures. Modern JavaScript applications, both client-side and server-side (Node.js), must treat prototype pollution as a high-priority vulnerability that demands both code-level analysis and dependency auditing to detect.

How it works

1

Identify merge or extend function

The attacker locates an endpoint that processes JSON input through a recursive merge, deep clone, or property assignment operation that does not filter prototype keys.

2

Inject __proto__ payload

A crafted JSON payload is submitted containing a __proto__ key with malicious property values, such as {"__proto__": {"isAdmin": true}} or {"constructor": {"prototype": {"polluted": true}}}.

3

Pollute Object prototype

The merge function processes the payload and assigns the attacker-controlled properties to Object.prototype, making them accessible on every object in the application.

4

Trigger secondary vulnerability

The polluted property is consumed by application logic elsewhere, leading to XSS (through polluted template variables), RCE (through polluted shell command options), or DoS (through corrupted application state).

Common causes

Recursive merge without key filtering

Custom or library-provided deep merge functions that iterate over all keys including __proto__ and constructor.prototype without checking whether they reference the object prototype chain.

Vulnerable library versions

Older versions of widely-used libraries like lodash (before 4.17.12), jQuery ($.extend in deep mode), and minimist contain prototype pollution vulnerabilities that are well-documented and easily exploited.

JSON.parse with unchecked keys

Parsing user-supplied JSON and passing the result directly to merge or assign operations without validating or sanitizing the key names. JSON.parse preserves __proto__ as a regular property key.

Object.assign and spread misuse

Using Object.assign or spread operators to merge user-controlled objects with application configuration or default settings. While shallow spread is safer, nested patterns combined with other operations can still enable pollution.

How to detect it

Automated detection

  • SecPortal's code scanner uses Semgrep rules to detect unsafe merge patterns, recursive property assignment without key filtering, and direct use of known vulnerable library functions
  • SCA (software composition analysis) scanning identifies dependencies with known prototype pollution CVEs, including vulnerable versions of lodash, minimist, Hoek, and set-value
  • SAST analysis traces data flow from user input (request body, query parameters) through merge or assign operations to identify exploitable prototype pollution sinks

Manual testing

  • Submit JSON payloads containing __proto__ keys to API endpoints and check whether the injected properties appear on unrelated objects in subsequent responses
  • Review package.json and lock files for dependencies with known prototype pollution advisories using npm audit or Snyk
  • Audit custom merge, clone, and extend utility functions in the codebase for missing __proto__ and constructor key filtering

How to fix it

Use Object.create(null) for lookup objects

Create objects without a prototype chain by using Object.create(null). These objects do not inherit from Object.prototype, so polluting the prototype has no effect on them. Use this pattern for configuration objects, caches, and maps.

Freeze prototypes

Call Object.freeze(Object.prototype) early in your application startup to prevent any modifications to the base prototype. This is a defense-in-depth measure that blocks pollution attempts at runtime.

Validate and sanitize object keys

Before merging user-supplied objects, filter out dangerous keys including __proto__, constructor, and prototype. Implement an allow-list of expected keys rather than a deny-list to ensure comprehensive protection.

Update vulnerable libraries

Keep dependencies up to date. Replace vulnerable versions of lodash, jQuery, minimist, and similar libraries with patched versions. Run regular dependency audits as part of your CI/CD pipeline to catch new advisories.

Use Map instead of plain objects

For dynamic key-value storage where keys come from user input, use JavaScript Map objects instead of plain objects. Maps do not have a prototype chain that can be polluted and provide a cleaner API for dynamic data.

Compliance impact

Find prototype pollution in your code

SecPortal's code scanner detects unsafe merge, extend, and deep clone patterns that enable prototype pollution. Start free.

No credit card required. Free plan available forever.