prototype-pollution
Skill2 starsChanged 4 months agoMITView on GitHub
SAST detection methodology for JavaScript/Node prototype pollution (CWE-1321), including client-side PP feeding DOM XSS gadgets and server-side PP escalating to RCE via child_process and template-engine option gadgets. Covers vulnerable recursive merge/extend/clone/set utilities, __proto__/constructor.prototype keys, and nested-object parsers. Use when reviewing JS that merges, clones, or deep-sets objects from untrusted input. Writes confirmed findings to findings/14-prototype-pollution.md.
- Reads credentials
10 other projects use a version of this.
Adopted by
Most recently taken up by
- mahumadad/quarrytheir own version, first seen Nov 8, 2026
- awarexone/AXguardtheir own version, first seen Sep 15, 2026
- ajtazer/heckittheir own version, first seen Sep 11, 2026
- emre-guler/websectheir own version, first seen Aug 27, 2026
- conjure-3301/skillstheir own version, first seen Aug 17, 2026
- Kur1sulab/blackboxtheir own version, first seen Aug 12, 2026
Used with
Projects with it also use path-traversal, prompt-injection and 4 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
langbyyiSkillpath-traversal
Path traversal and LFI playbook. Use when file paths, download endpoints, include operations, archive extraction, or wrapper behavior may expose filesystem control.
Also in 4 projects that use this
wgpsecSkillprompt-injection
AI/LLM 间接 Prompt 注入攻击。当目标 AI 系统会处理外部数据源(网页、文档、邮件、数据库、API 返回)时使用。覆盖间接注入、工具链劫持、RAG 投毒、数据外泄等技术。OWASP LLM Top 10 #1 漏洞类别
Also in 3 projects that use this
SubhiSecSkillssti
Hunt Server-Side Template Injection (SSTI) in Jinja2, Twig, Freemarker, Velocity, Smarty, ERB, Handlebars, Mustache, and Spring (SpEL). Use when input is reflected in a way that suggests template rendering — error pages, email templates, PDF generators, dynamic content systems.
Also in 3 projects that use this
SubhiSecSkillxss
Hunt reflected, stored, and DOM-based Cross-Site Scripting (XSS) including CSP bypass, polyglot payloads, mutation XSS (mXSS), markdown XSS, and template XSS. Use when the user has identified a parameter or input that reflects to the page, or wants to test for XSS in a specific input.
Also in 3 projects that use this
iAskShahramSkillfile-upload
Uploads a local file to Cloudflare R2 bucket `public` with wrangler and returns the public URL on assets.shahram.dev. Use when the user wants a public link, public URL, or to host/upload a local image or file to R2.
Also in 4 projects that use this
- +1 more from SubhiSec
Other versions10 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 10
- yaklang/hack-skills★ 2.4ksame name
- thejefflarson/soundcheck★ 20same name
- awarexone/AXguard★ 17same name
- langbyyi/websec-skills★ 4same name
- Kur1sulab/blackbox★ 3same name
- ajtazer/heckit★ 2same name
- emre-guler/websec★ 2same name
- JustineDevs/premortem★ 2same name
- mahumadad/quarry★ 1same name
- conjure-3301/skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository49 other files it gives its agents.
- authentication-flawsSkill
- broken-access-control-idorSkill
- business-logic-flawsSkill
- cicd-and-pipeline-injectionSkill
- code-injectionSkill
- command-injectionSkill
- cors-misconfigurationSkill
- crlf-and-header-injectionSkill
- cross-site-scriptingSkill
- csrfSkill
- dependency-and-supply-chainSkill
- dom-clobbering-and-postmessageSkill
- graphql-injection-and-abuseSkill
- hardcoded-secretsSkill
- http-request-smugglingSkill
- iac-misconfigurationSkill
- information-disclosureSkill
- insecure-deserializationSkill
- insecure-randomnessSkill
- jwt-vulnerabilitiesSkill
- ldap-injectionSkill
- llm-and-ai-application-securitySkill
- mass-assignmentSkill
- memory-safetySkill
- mobile-android-securitySkill
- mobile-ios-securitySkill
- nosql-injectionSkill
- oauth-oidc-saml-flawsSkill
- open-redirectSkill
- path-traversal-and-file-inclusionSkill
- race-conditions-and-toctouSkill
- redosSkill
- sast-final-reportSkill
- sast-finding-validationSkill
- sast-methodologySkill
- security-logging-and-monitoring-failuresSkill
- security-misconfiguration-and-headersSkill
- server-side-template-injectionSkill
- session-managementSkill
- smart-contract-securitySkill
- sql-injectionSkill
- ssrfSkill
- unrestricted-file-uploadSkill
- unsafe-parsers-and-yamlSkill
- weak-cryptographySkill
- web-cache-poisoning-and-deceptionSkill
- websocket-securitySkill
- xpath-and-xml-injectionSkill
- xxeSkill
The file
We split this skill into the rules it gives an agent
3 rules. 0 are common, 0 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 9 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 43
All HTTP inputs where the attacker controls object keys, not just values: JSON request bodies (arbitrary keys), query strings parsed into …
- Very specific: line 97
Use Object.create(null) (null-prototype) or Map for untrusted key/value stores — no Object.prototype to pollute.
- Very specific: line 187
Low/Info: if pollution is confirmed but no gadget/sink is reachable.
“Common” is measured: kept by at least 6 in 10 of the 9 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Prototype Pollution — SAST Methodology
Class: Prototype Pollution · CWE-1321 · OWASP: A08 Software & Data Integrity Failures
Findings file: findings/14-prototype-pollution.md
1. Overview
Prototype pollution occurs when attacker-controlled keys reach an object-mutation
operation that walks a property path (__proto__, constructor, prototype) and
writes onto Object.prototype instead of the intended object. Because nearly all
JS objects inherit from Object.prototype, a single injected property becomes a
default on every object, altering program logic globally. The core test: does a
source supply both the key(s) and value to a recursive merge/set/clone that
does not block __proto__/constructor/prototype segments?
2. Where it lives
- Config/option merging:
Object.assignmisuse,lodash.merge/_.merge/_.mergeWith/_.defaultsDeep/_.set/_.setWith,jQuery.extend(true, …)(deep),deep-assign,merge-deep,deep-extend, hand-rolleddeepMerge. - Nested-object builders: query-string parsers (
qs, olderexpressbody parsing) and body parsers that expanda[b][c]=vor dotteda.b.c=vinto nested objects. - Generic "set property by path" helpers (
set(obj, path, val)), and JSON-to-object hydration that trusts keys. - Client-side: URL/
location.hash/postMessageparsed into a config object then merged; server-side: request body/query merged into defaults or into a template-engine/child_processoptions object.
3. Sources (tainted input)
All HTTP inputs where the attacker controls object keys, not just values:
JSON request bodies (arbitrary keys), query strings parsed into nested objects
(?__proto__[x]=y, ?constructor[prototype][x]=y, ?a.b.c=y), URL fragments,
postMessage payloads, and any deserialized structure (YAML/JSON config, stored
documents) whose keys are attacker-influenced. Second-order: a polluted value
stored and later merged into a fresh object.
4. Sinks (dangerous operations)
// Vulnerable recursive merge — dangerous
function merge(target, source) {
for (const key in source) { // key can be "__proto__"
if (typeof source[key] === 'object')
merge(target[key], source[key]); // walks into Object.prototype
else
target[key] = source[key]; // writes global default
}
}
merge({}, JSON.parse(req.body));
// Library sinks — dangerous with attacker-controlled keys
_.merge({}, req.body); // lodash <4.17.12
_.defaultsDeep({}, req.query);
_.set(obj, req.query.path, req.query.val); // path = "__proto__.polluted"
$.extend(true, {}, userSuppliedObject); // jQuery deep extend
Object.assign(config, ...); // shallow, but a[__proto__] on nested merge
// Nested-object parser — dangerous
const q = qs.parse(req.url.split('?')[1]); // ?__proto__[admin]=true// Server-side PP → RCE gadget: child_process options
const opts = merge({}, req.body); // pollutes Object.prototype.shell / .env / .NODE_OPTIONS
child_process.execSync('ls', opts); // shell / env now attacker-influenced
child_process.spawn(cmd, args, opts); // gadget: options.shell, options.env
// Server-side PP → RCE gadget: template engine options
// pollute Object.prototype with pug/handlebars compile internals, e.g.
// __proto__.outputFunctionName / .compileDebug / .client → injected JS in compiled fn
res.render('view', userData); // engine reads polluted defaults// Client-side PP → DOM XSS gadget
// pollute __proto__.src / .innerHTML / .attributes so a library that reads a
// missing option falls through to the polluted prototype value:
element.innerHTML = config.template || ''; // config.template undefined → prototype hit5. Sanitizers / safe patterns
Safe:
- Block dangerous keys before writing: reject/skip
__proto__,constructor,prototypepath segments in any recursive walk. - Use
Object.create(null)(null-prototype) orMapfor untrusted key/value stores — noObject.prototypeto pollute. Object.freeze(Object.prototype)as a hardening layer.- Schema validation (JSON Schema/
ajvwithadditionalProperties:false,zod,joi) that rejects unknown keys before any merge. - Patched library versions: lodash ≥ 4.17.21,
qscurrent, that guard__proto__. JSON.parsereviver that drops__proto__keys;hasOwnPropertychecks in the merge loop (Object.hasOwn(source, key)won't help alone — see fails).
Fails / not a real sanitizer:
- Blocking only
__proto__but notconstructor.prototypeor the bracket form["__proto__"]/["constructor"]["prototype"]. hasOwnPropertyfiltering on the source only — the target traversal (target[key]) is where__proto__resolves to the prototype; you must guard the key name, not just own-ness.- Sanitizing top-level keys but recursing without re-checking nested keys.
- Removing
__proto__as a literal string but the parser having already created a real prototype link (JSON.parsedoes not, butqs/dotted parsers may). - Freezing a subclass prototype while
Object.prototypestays writable. - Version pin claimed but a transitive dependency ships the vulnerable merge.
6. Detection methodology
- Find merge/set/clone sinks:
rg -n '\b(_\.|lodash\.)(merge|mergeWith|defaultsDeep|set|setWith)\b|\bmergeDeep\b|deep-?assign|deep-?extend|merge-deep' rg -n '\$\.extend\(\s*true|jQuery\.extend\(\s*true|Object\.assign\(' rg -n 'for\s*\(\s*(const|let|var)?\s*\w+\s+in\s+\w+\)' # hand-rolled recursive merge - Find nested-object parsers:
rg -n "qs\.parse|querystring\.parse|require\(['\"]qs['\"]\)|extended:\s*true" rg -n 'set\(\s*\w+\s*,\s*\w*(path|key)' # set-by-path helpers - Confirm attacker controls keys: does the source supply object keys (JSON
body,
a[b][c]/a.b.cquery expansion), not only values? - Check for a key guard on the path: is
__proto__/constructor/prototypeblocked in all forms (dotted, bracket, nested)? Is the store a null-prototype object/Map? Is there schema validation rejecting unknown keys? (see §5) - Classify the impact / find the gadget:
- Client-side → look for a library that reads an unset option and falls through
to the prototype (
config.x || default), feeding a DOM XSS/src/innerHTMLsink. - Server-side → look for a downstream
child_process(optionsshell/env), template render, or other library reading polluted defaults → RCE.
- Client-side → look for a library that reads an unset option and falls through
to the prototype (
- Confirm reachability: is the sink on an exposed route/handler, pre-auth?
7. Modern & niche variants
- Client-side PP → DOM XSS gadget chain: pollution alone rarely executes; it
arms a gadget — a library reading a normally-unset property that flows into an
HTML/
src/scriptsink (jQuery, sanitizer configs, ad/analytics loaders, Google Tag Manager, sanitize-html option defaults). Report PP + the reachable gadget as a chain, not just the pollution. - Server-side PP → RCE: the highest-severity form. Gadgets:
child_processoptions: pollutingObject.prototype.shell = '/bin/sh',.env,.NODE_OPTIONS='--require /proc/self/…', or argument arrays so a laterspawn/exec/forkruns attacker commands.- Template-engine options: Pug/Handlebars/EJS/Lodash templates read compile
options off the prototype (
compileDebug,client,outputFunctionName, delimiters) → injected JS in the compiled render function → RCE onres.render.
- Vulnerable utilities:
lodash.merge/mergeWith/defaultsDeep/set/setWith(pre-patch),jQuery.extend(true, …),deep-assign,merge-deep,deep-extend,hoek/assign, and any hand-rolled recursivefor…inmerge without a key guard. - Key forms to test:
__proto__,constructor.prototype, bracket["__proto__"],["constructor"]["prototype"], and dotteda.__proto__.b/a[__proto__][b]produced by query-string/dotted-path parsers. A guard that misses any one form is bypassable. - Parser-built nesting:
qs/expressextended body parsing and dotted-path expanders create the nested__proto__object automatically from flat input — the developer never wrote a merge but the parser did the walk.
8. Common false positives
- Merges where keys are developer-controlled constants, not from a source.
- Stores built on
Object.create(null)/Map, or validated by strict schema (additionalProperties:false) before merging. - Patched library versions with a documented
__proto__guard, and no vulnerable transitive copy. - Shallow
Object.assign/spread of a flat, key-validated object (no recursion, no attacker-controlled__proto__at top level after guard). - Pollution with no reachable gadget/sink (still note as low/info if source→sink of the pollution is confirmed but no impact path exists).
9. Severity & exploitability
Base High. Critical when a reachable gadget escalates to RCE (server-side
child_process/template-engine option gadget) or to auth bypass (polluting an
isAdmin/role default that a downstream check reads). Medium/High for
client-side PP that arms a DOM XSS gadget (chain severity = the XSS impact).
Low/Info if pollution is confirmed but no gadget/sink is reachable. Raise for
pre-auth, default-config-vulnerable dependencies. See references/severity-model.md.
10. Remediation
Reject __proto__/constructor/prototype keys in every recursive merge/set in
all forms (dotted, bracket, nested). Store untrusted key/value data in
Object.create(null) objects or Map. Validate input against a strict schema
(additionalProperties:false) before merging. Upgrade lodash/qs/merge utilities
to patched versions and check transitive deps. Object.freeze(Object.prototype) as
defense-in-depth. Avoid deep-merging untrusted input into option objects consumed
by child_process or template engines.
11. Output
Append each confirmed finding to findings/14-prototype-pollution.md using
references/finding-template.md. Set Class: Prototype Pollution, CWE: CWE-1321,
and in Chain potential name the primitive precisely: global property injection
(consumes attacker keys; provides a gadget trigger) → then name the reachable
gadget it feeds: RCE via child_process/template-engine options, DOM XSS via
library gadget (chains into cross-site-scripting), or auth-flag bypass. PP is
almost always reported as a chain with its gadget — always identify the
downstream sink the pollution reaches.
Primitives (controlled): provides GADGET (-> CODE_EXEC server / JS_EXEC client); consumes none
References
- CWE-1321; OWASP A08:2021; PortSwigger prototype-pollution research (client & server); Snyk/lodash & qs advisories; "Server-Side Prototype Pollution" gadget catalogues.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

