Mar 13, 2026·6 min read·3 visits
The devalue npm package (< 5.6.4) improperly parses objects containing `__proto__` as an own property. This enables prototype pollution attacks if the resulting objects are processed by vulnerable merge logic in downstream applications.
The devalue library prior to version 5.6.4 contains a prototype pollution vector within its deserialization routines. The `parse` and `unflatten` functions fail to validate property keys, allowing the instantiation of objects with `__proto__` as an explicit own property. This behavior facilitates prototype pollution when the resulting objects are processed by applications using insecure recursive merge functions.
Modern web applications rely on state hydration mechanisms to synchronize server-side data with client-side execution environments. Frameworks such as SvelteKit utilize the devalue library to serialize complex JavaScript application state. This library is preferred over standard JSON.parse and JSON.stringify because it correctly handles complex data types including cyclical references, BigInt, Map, Set, RegExp, and Date objects.
The serialization process involves converting these complex structures into a custom string format, which the devalue parser later reconstructs into memory. A vulnerability exists within this reconstruction phase in versions prior to 5.6.4. The parsing logic fails to enforce strict constraints on property keys during object instantiation.
Specifically, the parse and unflatten functions do not sanitize the __proto__ key. This oversight permits an attacker to construct serialized payloads that emit JavaScript objects containing __proto__ as an explicit own property. This issue is tracked under CWE-1321 (Improperly Controlled Modification of Object Prototype Attributes).
JavaScript utilizes a prototype-based inheritance model where objects inherit properties from Object.prototype via the __proto__ accessor property. Under normal operations, accessing or assigning to __proto__ interacts with the prototype chain. However, an object can be constructed to possess __proto__ as an explicit own property, shadowing the inherited accessor.
The devalue parsing mechanism aims to reconstruct original structures by iterating through the serialized string and assigning properties directly to newly instantiated objects. When the parser encounters a property named __proto__ within an object wrapper payload, it assigns the corresponding value directly to the object instance. The library frequently uses standard object literals {} for instantiation during this process.
Because the assignment applies to the explicit own property rather than the prototype accessor, the instantiation itself does not immediately pollute the global Object.prototype. The root cause is the creation of a malicious carrier object. This carrier object correctly traverses the devalue boundary but carries a weaponized __proto__ property that exposes downstream application logic to prototype pollution attacks.
The vulnerability resides in the object reconstruction routines of the devalue library. Prior to version 5.6.4, the internal logic iterated over the keys defined in the serialized payload without validating their names. The resulting state allowed the __proto__ key to pass directly into the property assignment phase.
The maintainers addressed this flaw through two specific commits targeting the core reconstruction paths. Commit 87c1f3c updates the standard parse function to explicitly validate keys within Object wrappers. The patch introduces a strict equality check against the __proto__ string. If the parser detects this key, it immediately throws an error, rejecting the malformed payload entirely.
Commit 40f1db1 applies a similar structural fix to the unflatten utility. The unflatten function is responsible for resolving internal cyclical references by reconstructing objects from a flattened array representation. The patch ensures that the unflattening logic properly ignores or safeguards against __proto__ own properties. The patched logic prevents the assignment of the key, ensuring the carrier object cannot be constructed.
// Conceptual representation of the patched logic
function parseObjectWrapper(payload) {
const obj = {};
for (const key in payload) {
// Patch: Explicit rejection of prototype modifications
if (key === '__proto__') {
throw new Error('Disallowed key __proto__');
}
obj[key] = unflatten(payload[key]);
}
return obj;
}Exploitation of this vulnerability requires a specific attack chain involving two distinct components. The attacker must first target an application endpoint that accepts external input and deserializes it using devalue.parse. This is a common pattern in SvelteKit applications processing server-side rendered state or complex API responses.
The attacker crafts a custom serialized string representing an object with a __proto__ key. For example, a payload is designed to evaluate to { "__proto__": { "polluted": "success" } }. The application invokes devalue.parse on this payload, returning the carrier object into the application's operational memory.
The secondary requirement for exploitation is the presence of an insecure recursive merge operation. Many applications utilize deep merge functions to combine parsed state with existing configuration objects. When the merge logic iterates over the carrier object, it accesses the explicit __proto__ own property.
If the merge function fails to validate keys before assignment, it traverses into the Object.prototype of the target object. The malicious properties are then applied globally, successfully completing the prototype pollution attack.
The concrete security impact of this vulnerability is contingent upon the downstream application context. The direct result of the attack chain is the modification of properties on the global Object.prototype. The severity depends on which properties are polluted and how the application subsequently utilizes them.
In client-side contexts, prototype pollution frequently facilitates Cross-Site Scripting (XSS) or Denial of Service (DoS). Attackers can manipulate application state, disrupt expected object shapes, or alter rendering logic. This often results in unauthorized script execution within the context of the user's browser.
In server-side Node.js environments, the consequences extend to Remote Code Execution (RCE). If an attacker pollutes configuration properties used by core modules, such as the env or shell options in child_process.exec, they can intercept execution flows to run arbitrary system commands. The CVSS base score of 5.3 (C:N/I:L/A:N) reflects the primary impact of the pollution vector itself, though the secondary context can elevate the ultimate severity.
The primary remediation for this vulnerability is upgrading the devalue package. Sveltejs maintainers have released version 5.6.4, which introduces the necessary key validation checks. Development teams must update their dependencies and verify the installed version via their respective package lockfiles.
Organizations utilizing SvelteKit should verify their framework version, as it directly bundles devalue for state hydration. Running npm update devalue or the equivalent command for the active package manager will pull the patched release. Automated security scanners should be configured to flag any devalue installation prior to 5.6.4.
As a defense-in-depth measure, security teams must audit all custom and third-party deep merge implementations across their codebase. Recursive merge functions must be heavily scrutinized to ensure they are prototype-aware. These utilities must explicitly reject __proto__, constructor, and prototype keys before proceeding with assignment operations.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
devalue Sveltejs | < 5.6.4 | 5.6.4 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1321 |
| Attack Vector | Network |
| CVSS Base Score | 5.3 |
| Impact | Integrity (Prototype Pollution), potential DoS/RCE |
| Exploit Status | Proof-of-Concept Available |
| CISA KEV | Not Listed |
Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')