From soundcheck
Detects and fixes prototype pollution (CWE-1321) in JavaScript/TypeScript code using deep merges, lodash merge/set, Object.assign with dynamic keys, or recursive copies on user input.
npx claudepluginhub thejefflarson/soundcheck --plugin soundcheckThis skill uses the workspace's default tool permissions.
Protects against prototype pollution in JavaScript/TypeScript where an attacker injects
Detects prototype pollution in JavaScript/TypeScript code by auditing object merge, clone, assign operations and untrusted input handling. Guides impact assessment for CVSS scoring.
Detects and exploits prototype pollution in JavaScript/Node.js apps via URL/JSON payloads for XSS, RCE, and auth bypass. For security testing web APIs and client-side code.
Detects and exploits JavaScript prototype pollution in client-side and server-side apps for XSS, RCE, and auth bypass via property injection. Useful for pentesting Node.js APIs, JSON merges, and JS frameworks.
Share bugs, ideas, or general feedback.
Protects against prototype pollution in JavaScript/TypeScript where an attacker injects
properties like __proto__ or constructor.prototype through user input, modifying
the prototype chain of all objects. Exploitation leads to property injection, auth
bypass, and remote code execution in some frameworks.
_.merge(config, userInput) — lodash merge recurses into __proto__Object.assign(target, JSON.parse(body)) — copies __proto__ key if presentfunction deepMerge(t, s) { for (k in s) t[k] = ... } — custom merge without key filterobj[req.body.key] = req.body.value — dynamic property set on arbitrary keyFlag the vulnerable code and explain the risk. Then suggest a fix that establishes these properties:
__proto__, constructor, prototype. The filter runs
before assignment, not after; a post-hoc delete obj.__proto__ doesn't help
because the prototype chain was already mutated.obj[userKey] = value) validates the key
against a blocklist, or sidesteps the issue by using a Map instead. A
Map has no prototype chain exposure; obj[userKey] does.Object.create(null) when keys come from
input. A null-prototype object cannot be polluted because there is no
prototype chain to reach._.merge, _.set, and jQuery $.extend(true, …) on untrusted
input are replaced with key-filtered wrappers or safe alternatives. The
issue is library-version-dependent, so relying on patched versions is
fragile; filter at the call site.Anchor — shape, not implementation:
const BAD = new Set(["__proto__", "constructor", "prototype"]);
function safeMerge(t, s) {
for (const k of Object.keys(s)) { // not `for ... in`
if (BAD.has(k)) continue;
t[k] = (isObj(s[k]) && isObj(t[k])) ? safeMerge(t[k], s[k]) : s[k];
}
return t;
}
// or: const config = Object.create(null); // no prototype to pollute
__proto__, constructor, and prototype keysobj[userKey] = value) validates the key against a blocklist or uses Map instead_.merge on untrusted input is replaced with a safe alternative or key-filtered wrapper