CtrlK
BlogDocsLog inGet started
Tessl Logo

prototype-pollution

Hunt JavaScript prototype pollution (CWE-1321) — the 2023-2026 meta-vulnerability that chains into RCE, auth bypass, and SSRF on most Node.js stacks.

58

Quality

68%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Critical

Do not install without reviewing

Fix and improve this skill with Tessl

tessl review fix ./packages/decepticon/decepticon/skills/standard/analyst/prototype-pollution/SKILL.md
SKILL.md
Quality
Evals
Security

Prototype Pollution Playbook

Prototype pollution is the JavaScript equivalent of a universal gadget: plant a property on Object.prototype and it appears on every object in the runtime. Worthless in isolation, deadly in chain (__proto__.isAdmin = true → auth bypass; __proto__.shell = "/bin/bash" → RCE via spawn).

1. Sinks — the libraries that still introduce sinks

Keep a running list per engagement. These continue to ship sinks in 2026:

  • Deep-merge: lodash.merge, deepmerge (pre-fix), merge-deep, deepExtend, hoek.merge, mixme
  • Deep-clone: lodash.defaultsDeep, lodash.zipObjectDeep, set-value (pre-3.0.3)
  • URL-to-obj: qs, express-fileupload, jquery.extend(true, ...)
  • Config loaders: node-config recursive merge, dotenv-extended, rc
  • Template engines: Handlebars helpers fed from untrusted ctx
# Every JS/TS project: sweep known-bad versions
jq '.dependencies,.devDependencies | to_entries[] | select(.key | test("merge|lodash|set-value|dot-object|dot-prop|node-pg"))' /workspace/src/package.json
npm ls lodash set-value dot-prop 2>/dev/null | grep -E '[0-9]'

2. Sources

Any user input deserialized into a nested object:

  • JSON body parsers (body-parser, express.json)
  • Query string parsers (qs with default config parses a[b][__proto__][c]=1)
  • YAML uploads
  • Form-data / multipart

3. Audit workflow

  1. Find every deep merge call site.
  2. Trace each one backwards — is the right-hand object user-controlled?
  3. If yes: check the merge function's prototype-pollution fix version.
  4. Even if the merge is fixed, check whether a copy (lodash.set, dot-path-value, jsonpath.set) creates a pollution path.

4. Exploitation gadgets

Poisoning Object.prototype doesn't do anything by itself — you need a gadget that reads a property that didn't exist before.

Classic gadgets:

  • child_process.spawn(cmd, args, opts) — opts has a shell option. Poison __proto__.shell = "/bin/bash" then any subsequent spawn call executes through bash and interprets args as shell strings.
  • Express middleware — most middlewares check options.someFlag with if (opts.someFlag). Poisoning that flag flips security defaults.
  • Templating — Handlebars and EJS read helpers and partials from the context object; pollution adds helpers that execute code.
  • lodash.template — if the template source is built from _.template(tpl, ctx) you can inject via polluted escape/evaluate keys.
  • mongoose — polluting Schema.Types causes subsequent schema definitions to use attacker-controlled types.

5. PoC template

# Classic lodash.merge RCE via child_process.spawn
curl -X POST https://target.com/api/settings \
  -H 'Content-Type: application/json' \
  -d '{"__proto__": {"shell": "/bin/bash", "env": {"PATH": "/tmp:/usr/bin"}}}'

# Second request triggers the gadget
curl https://target.com/api/render-pdf
# → any subsequent child_process.spawn call now runs through /bin/bash

6. Success signals for validate_finding

  • Server error with stack trace referencing Object.prototype
  • Output of injected command reflected in next response
  • Admin-only endpoint now returns 200 after poisoning __proto__.isAdmin

Negative control: same payload with proto (no leading underscores) — should have no effect. If it does, the endpoint is treating that key specially and the finding is unrelated.

7. Default CVSS

VariantVectorScore
DoS (crash Node process)AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H7.5
Auth bypass via isAdmin pollutionAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N9.1
RCE via spawn gadgetAV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H10.0

8. Chain promotion

Prototype pollution is almost always the first hop of a chain. After validation, add an enables edge from the pollution vuln to:

  • the spawn / template gadget vuln (RCE chain)
  • the auth check vuln (privilege escalation chain)
  • the SSRF vuln if the downstream request lib has an options pollution surface

Chain weight 0.4 — pollution is cheap once the merge sink is known.

Repository
PurpleAILAB/Decepticon
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.