prototype-pollution

Prototype pollution testing for JavaScript stacks. Use when user input is merged into objects (query parsers, JSON bodies, deep assign), when configuring libraries via untrusted keys, or when hunting RCE gadgets via polluted Object.prototype in Node or the browser.

By yaklang · 2,958 installs

npx skills add yaklang/hack-skills --skill prototype-pollution

Source repository · Upstream listing

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 When input can reflect into DOM or framework routing, pair with alert(1) / console checks to observe whether global object properties were polluted. Server side first probes(JSON / form) 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: 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 If router or analytics code parses fragments into objects and then merges, pollution may occur. constructor.prototype path DOM / attribute injection ideas If the framework merges attribute names as object keys: Event handler style keys (implementation dependent): 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}} Multi parameter parsing in follow up requests is ignored or abnormal ( qs style parameterLimit ) {" proto ":{"ignoreQueryPrefix":true}} Double question mark prefixes like ??foo=bar are accepted or behavior changes sharply {" proto ":{"allowDots":true}} Nested keys like ?foo.bar=baz are expanded via dot notation {" proto ":{"json spaces":" "}} JSON serialized responses gain extra spaces ( JSON.stringify spacing setting polluted) {" proto ":{"exposedHeaders":["foo"]}} CORS responses include foo related headers (if framework reads config from prototype) {" proto ":{"status":510}} Some response status changes to 510 or another abnormal code (app reads status from object) Operational tip : send pollution request first, then a clean request to observe persistence; connection pools and worker lifecycle affect whether impact is globally visible. 4. EXPLOITATION GADGETS Target / scenario Payload or pattern Notes EJS {" proto ":{"client":1,"escapeFunction":"JSON.stringify; process.mainModule.require('child process').exec('COMMAND')"}} If template engine options like escapeFunction are read from polluted prototype, this may lead to RCE; strongly version/config dependent Timelion expression chain (CVE 2019 7609) .es( ).props(label. proto .env.AAAA='require("child process").exec("COMMAND")') Historical chain: prototype pollution + timeline expression execution; useful to understand expression + PP combinations Node child process Pollute shell , argv0 , env , NODE OPTIONS , etc. (merged into exec / fork option objects) Depends on whether later code calls spawn / fork and reads options from prototype chain Generic constructor path {"constructor":{"prototype":{"foo":"bar"}}} Bypasses weak validation that filters only the proto key Chain mindset : pollution dependency reads obj.settings.xxx without hasOwnProperty RCE / SSRF / path traversal. 5. TOOLS Project Purpose yeswehack/pp finder Helps locate PP prone merge points and patterns yuske/silent spring Research and detection around prototype pollution surfaces yuske/server side prototype pollution Server side PP testing suite/methodology BlackFan/client side prototype pollution Browser side PP cases and payloads portswigger/server side prototype pollution Burp ecosystem extension / supporting material msrkp/PPScan Scanning/verification helper Prioritize use on authorized targets; automated tools can cause side effects on stateful applications. 6. DECISION TREE Related routing Input routing and multi injection parallel entry [Injection Testing Router](../injection checking/SKILL.md). Template execution chains (non PP) [SSTI](../ssti server side template injection/SKILL.md). Insecure deserialization (non JS prototype) [Deserialization](../deserialization insecure/SKILL.md).