Skip to content
Vulnerabilities

Prototype Pollution: How Object Injection Breaks Your Logic

Modifying an object’s prototype allows attackers to inject properties that every instance inherits, bypassing standard checks silently.

Illustration: A single blue software object floats in white space, its core structure cracking open to release tiny, identical copies.
AI-generated illustration: Phish Herald
Quick answer

Prototype pollution occurs when an attacker injects properties into a JavaScript object’s prototype. This causes those properties to appear on all objects inheriting from it. It enables logic bypasses, privilege escalation, and denial of service. You must avoid unsafe merging functions and validate inputs strictly.

What is prototype pollution?

Prototype pollution is a vulnerability class in JavaScript where an attacker injects properties into the prototype of a native object. JavaScript objects inherit properties from a prototype chain, which acts as a blueprint for shared characteristics. When an attacker modifies this blueprint, every object that inherits from it gains the new, malicious properties. This allows the attacker to alter application logic without touching the individual objects directly.

Infographic: Prototype Pollution: How Object Injection Breaks Your Logic. Unsafe merge functions like recursive copy operations are the primary attack vector. The attack modifies the prototype chain, affecting all future objects created in that context. Standard input validation often fails because
Infographic: Prototype Pollution: How Object Injection Breaks Your Logic. Free to share with a link to Phish Herald.

Why does this matter for server-side applications?

Server-side JavaScript environments like Node.js execute code that handles user input and business logic. If an application merges user-supplied data with internal configuration objects using an unsafe method, the server’s memory state changes globally. This can lead to remote code execution if the injected property is later evaluated. It can also cause denial of service by crashing the application when it encounters unexpected data types. The impact is systemic because the pollution persists for the lifetime of the process.

How do attackers trigger this vulnerability?

Attackers typically exploit functions that recursively merge objects, such as deep copy or extend utilities. Suppose an application accepts a JSON payload to update user settings. If the backend uses a flawed merge function, the attacker can send a payload containing __proto__ or constructor.prototype. The merge function writes these keys into the object’s prototype rather than as direct properties. This subtle distinction allows the injection to propagate silently through the application’s object hierarchy.

Which functions are most at risk?

Functions that perform recursive object merging are the most common culprits. Libraries that provide utility functions for combining configuration objects often contain these flaws. If a function iterates over the keys of a source object and assigns them to a target object without checking for prototype keys, it is vulnerable. Even custom-written merge logic can fail if it does not explicitly block access to the prototype chain. Developers often assume that assigning a key creates a local property, but JavaScript’s dynamic nature allows prototype modification.

How does this relate to input validation?

Standard input validation checks the format and content of data before it enters the system. However, prototype pollution often bypasses these checks because the malicious payload looks like valid JSON or form data. The danger arises during the processing phase, not the intake phase. You must treat the merging of objects as a sensitive operation. Validating that input does not contain prototype-related keys is necessary but insufficient if the merging logic itself is flawed. Effective defence requires both strict input filtering and safe processing functions.

See also: Hardcoded Secrets Myths: Why Common Beliefs About Source Code Risks Are Wrong

Can this vulnerability be exploited in browsers?

Yes, client-side prototype pollution can occur in web applications that use vulnerable JavaScript libraries. Imagine a single-page application that merges user preferences with default settings. If an attacker can inject a script that modifies the prototype, they can alter the behaviour of the entire application for that session. This can lead to privilege escalation within the app, such as forcing an admin view. It can also facilitate cross-site scripting if the polluted property is rendered into the DOM without proper escaping.

What is the difference between this and other injection flaws?

Unlike SQL injection, which targets database queries, prototype pollution targets the application’s runtime memory. It does not require direct interaction with a database. The attack vector is the language’s object model rather than a query parser. This makes it distinct from path traversal vulnerabilities, which aim to access files outside the intended directory. Prototype pollution is about logic manipulation through inheritance, whereas path traversal is about file system navigation. Understanding this distinction helps in selecting the right mitigation strategies.

How do you detect prototype pollution in code?

Static analysis tools can identify calls to unsafe merge functions. You should look for libraries that are known to have had prototype pollution vulnerabilities in the past. Software composition analysis can help identify these dependencies in your project. However, automated tools may miss custom merge functions or complex logic flows. Manual code review is necessary to ensure that any function handling untrusted data does not write to the prototype. Check for the use of __proto__, constructor, and prototype keys in incoming data.

What is the most effective mitigation?

The most effective mitigation is to avoid using unsafe merge functions entirely. Use libraries that are explicitly designed to be prototype-pollution-safe. These libraries typically freeze the prototype or block assignment to prototype keys. If you must write custom merge logic, ensure it does not iterate over inherited properties. Use Object.create(null) to create objects without a prototype, which prevents pollution. This approach eliminates the inheritance chain that the attacker relies on. It is a structural defence that removes the attack surface rather than just filtering input.

Mitigation StrategyEffectivenessComplexity
Use safe librariesHighLow
Input filteringMediumLow
Code reviewHighHigh
Object freezingHighMedium

Does automatic software updates help?

Automatic software updates can help by ensuring your dependencies are patched quickly. However, they do not fix custom code that implements unsafe merging logic. You must still review your own code for vulnerabilities. Updates only address known flaws in third-party libraries. They do not protect against logic errors in your application’s core. Relying solely on updates leaves custom vulnerabilities exposed. Combine updates with rigorous code review practices.

How does this affect least privilege access?

Prototype pollution can bypass least privilege access controls by injecting properties that assert higher privileges. If an application checks for a property like isAdmin on a user object, an attacker can inject this property into the prototype. All user objects will then appear to have admin rights. This undermines the principle of least privilege by altering the truth of the data structure. You must ensure that privilege checks are performed against immutable data sources, not mutable object properties. This prevents attackers from spoofing permissions through prototype injection.

What about file upload vulnerabilities?

File upload vulnerabilities are distinct from prototype pollution, but they can be combined. An attacker might use prototype pollution to bypass file type checks during an upload process. If the check relies on an object property that can be polluted, the attacker can force the server to accept malicious files. This combination increases the risk significantly. You must validate file uploads independently of any object merging logic. Use strict file type validation and store uploads outside the web root. This limits the impact of any successful injection.

How do you test for this vulnerability?

Testing requires injecting prototype-related keys into all inputs that undergo merging. Use payloads that include __proto__, constructor, and prototype. Check if these keys appear on objects that were not directly modified. Automated scanners can help, but they may miss complex scenarios. Manual testing is essential to verify that the application logic handles these keys safely. Ensure that your test environment mimics production data flows. This helps identify edge cases where pollution might occur.

What is the long-term outlook?

As JavaScript remains dominant, prototype pollution will remain a relevant threat. New libraries and frameworks may introduce new vectors. Developers must stay educated on safe coding practices. The shift towards safer languages and stricter type systems may reduce the prevalence of this issue. However, legacy code will persist for years. Continuous monitoring and regular code reviews are necessary. The community is becoming more aware, leading to better tooling and standards. Vigilance is required to maintain security.

Key takeaways

  • Unsafe merge functions like recursive copy operations are the primary attack vector.
  • The attack modifies the prototype chain, affecting all future objects created in that context.
  • Standard input validation often fails because the pollution happens after data entry, during processing.
Bottom line

Prototype pollution exploits the inheritance model of JavaScript to inject global properties, bypassing standard logic checks. Audit your code for unsafe merge functions and replace them with secure alternatives immediately.

Frequently asked questions

Is prototype pollution the same as cross-site scripting?

No, prototype pollution is a data integrity issue that can lead to XSS, but they are distinct. XSS involves executing scripts in the browser, while pollution modifies object properties in memory.

Can I fix this by just filtering `__proto__`?

Filtering `__proto__` is a partial fix. Attackers can use other keys like `constructor` or `prototype`. You must use a safe merging function or freeze the prototype.

Does TypeScript prevent prototype pollution?

TypeScript helps by catching type errors at compile time, but it does not prevent runtime prototype modification. Unsafe runtime operations can still occur.

How do I know if my library is vulnerable?

Check the library’s changelog and security advisories. Use software composition analysis tools to scan your dependencies for known vulnerabilities.

How this guide was produced: written by the Phish Herald editorial team with AI assistance, checked against the public references listed below, and reviewed when the facts change. See our editorial policy or report an error.

Further reading

  1. FIRST: Common Vulnerability Scoring System
  2. MITRE CWE
  3. CISA Known Exploited Vulnerabilities Catalog
prototype pollutionjavascript securityobject injectionweb application security

Related stories

Orgs hit by CVSS 9.8: Patch ThemeREX Tantra CMS to block object injection

Security teams must patch ThemeREX Tantra CMS versions up to 2.9.0 immediately to mitigate a critical deserialization vulnerability.