All vulnerabilities
HighA08:2021CWE-1321Injection

Prototype Pollution

Prototype pollution lets attackers inject properties into JavaScript's Object prototype, affecting all objects in the application and potentially leading to remote code execution or authentication bypass.

What Is Prototype Pollution?

JavaScript objects inherit properties from their prototype chain. Prototype pollution occurs when an attacker can set __proto__ or constructor.prototype on an object, injecting properties that are then inherited by all objects in the application. This can bypass security checks, manipulate application logic, or lead to Remote Code Execution.

How It Works

A common vulnerable pattern — deep merge or recursive property assignment:

// Vulnerable deep merge — commonly found in utility functions
function merge(target, source) {
  for (const key of Object.keys(source)) {
    if (typeof source[key] === "object" && source[key] !== null) {
      target[key] = target[key] || {}
      merge(target[key], source[key])  // Recursively merges __proto__!
    } else {
      target[key] = source[key]
    }
  }
  return target
}
 
// Attacker sends:
const malicious = JSON.parse('{"__proto__": {"isAdmin": true}}')
merge({}, malicious)
 
// Now EVERY object in the app has isAdmin: true
console.log({}.isAdmin)  // true

Authentication bypass:

// isAdmin check reads from the object — but prototype pollution set it globally
if (user.isAdmin) {
  return res.json({ secret: "admin-data" })
}

Remote Code Execution (via gadget chains):

Prototype pollution combined with certain library functions (lodash template, EJS render, vm2) can be escalated to RCE. Many CVEs in popular npm packages are prototype pollution chains.

Real-World Impact

  • Authentication bypass — pollute isAdmin, isAuthenticated, role
  • DoS — crash the app by polluting properties it depends on
  • RCE — chain with template engines or process spawning gadgets
  • Data manipulation — affect all objects' default values

How to Fix

Use Object.create(null) for objects used as maps:

// Safe — no prototype chain to pollute
const config = Object.create(null)
config["key"] = "value"

Validate keys before assignment:

function safeMerge(target, source) {
  for (const key of Object.keys(source)) {
    if (key === "__proto__" || key === "constructor" || key === "prototype") {
      continue  // Skip dangerous keys
    }
    if (typeof source[key] === "object") {
      target[key] = target[key] || {}
      safeMerge(target[key], source[key])
    } else {
      target[key] = source[key]
    }
  }
}

Use structuredClone() instead of manual deep merge:

// Safe — built-in deep clone, prototype-pollution resistant
const cloned = structuredClone(sourceObject)

Use proven libraries — lodash ≥4.17.21, minimist ≥1.2.6 have patched their prototype pollution vulnerabilities.

What VibeWShield Detects

VibeWShield submits requests with __proto__, constructor, and prototype keys in JSON bodies and URL parameters, then checks whether subsequent requests reflect the polluted properties in responses or behavior changes.

#prototype-pollution#javascript#nodejs#injection

Free security scan

Test your app for Prototype Pollution

VibeWShield automatically checks for Prototype Pollution and 40+ other vulnerabilities using 63 scanners — in under 3 minutes, no signup required.

Scan your app free