CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-8QM3-746X-R74R
7.50.04%

Devaluing Security: Prototype Pollution in `devalue`

Alon Barad
Alon Barad
Software Engineer

Feb 20, 2026·5 min read·4 visits

PoC Available

Executive Summary (TL;DR)

The `devalue` library failed to block the `__proto__` key during object serialization. An attacker can supply a malicious JSON object which, when processed by `devalue` and subsequently executed by a JavaScript engine, modifies the prototype of the resulting object. This affects versions prior to 5.6.3.

A high-severity Prototype Pollution vulnerability has been discovered in `devalue`, a popular library used for serializing JavaScript values, particularly in Server-Side Rendering (SSR) contexts like Svelte and Nuxt. The flaw allows attackers to inject `__proto__` properties into serialized objects. When these objects are deserialized (typically via execution on the client side), the global `Object.prototype` becomes polluted, potentially leading to Denial of Service (DoS), Cross-Site Scripting (XSS), or logic bypasses in the target application.

The Hook: When JSON Isn't Enough

Let's talk about "Hydration." It's that magical moment in modern web development where the server hands off a static HTML page to the browser and says, "Here, you take over." To do this, the server needs to send the current state of the application—JavaScript objects, arrays, maybe even a Date or a RegExp—down the wire.

JSON.stringify is the boring, safe uncle at the party. He only handles primitives. He chokes on circular references, hates undefined, and doesn't know what a Map is. Enter devalue. It's the cool cousin that says, "Don't worry, I can serialize anything into executable JavaScript code."

And therein lies the rub. devalue doesn't just produce a data string; it produces code that is meant to be evaluated (often via eval or a new Function constructor implicitly). When you turn user input into executable code, you are dancing on the edge of a volcano. In this case, the volcano erupted because devalue forgot that JavaScript objects have a very special, very dangerous property lurking in the shadows.

The Flaw: The Magic of `__proto__`

The vulnerability stems from a fundamental quirk in JavaScript: the difference between how JSON.parse handles __proto__ and how the JavaScript engine handles object literals.

If you run JSON.parse('{"__proto__": {"a": 1}}'), you get a plain object with a key named __proto__. Safe. Boring. The prototype remains untouched because JSON is just data.

However, devalue takes that object and converts it into a string of JavaScript code to be run later. It iterates over the keys and builds a string like { __proto__: { a: 1 } }. When the browser executes this string, it sees an Object Literal. In this context, __proto__ is NOT just a key—it is a magical setter that mutates the object's prototype chain.

Because devalue didn't explicitly forbid this key, it acted as a bridge. It took safe data (from JSON.parse) and transformed it into a weapon (an Object Literal prototype setter). The moment that code executes on the client, boom—Object.prototype is polluted.

The Code: Ignorance Was Bliss

Let's look at the "before" and "after". The vulnerability existed because the library simply iterated over keys without asking questions. It was trusting. It assumed you wouldn't hand it a grenade.

The fix, applied in commit 0f04d4d678eac39ad5d7a07d1956275d7874e81c, is a classic "stop and scream" pattern. Instead of blindly looping, the maintainers introduced a hard check for the forbidden key.

Here is the essence of the patch:

// THE FIX (Simplified)
// src/stringify.js & src/uneval.js
 
const keys = Object.keys(thing);
for (const key of keys) {
  // The new security bouncer
  if (key === '__proto__') {
    throw new DevalueError(
      `Cannot stringify objects with __proto__ keys`,
      keys,
      thing,
      value
    );
  }
  // ... proceed with serialization
}

Notice the switch to Object.keys()? That's intentional. It ensures we are only looking at own properties. But the real hero is the if (key === '__proto__') check. It doesn't try to sanitize it. It doesn't try to be clever. It just throws an error and aborts the process. In security, failing fast is usually safer than trying to fix bad input.

The Exploit: From Input to Pollution

So, how do we weaponize this? We need a scenario where a server accepts JSON input, deserializes it, passes it to devalue, and sends the result to a client.

Step 1: The Payload

The attacker sends a POST request with a JSON body. This is valid JSON, so the server accepts it without complaint.

{
  "userInput": {
    "__proto__": {
      "isAdmin": true,
      "vulnerable": true
    }
  }
}

Step 2: The Transformation

The server parses this JSON. Now we have an object in memory with a key __proto__. The server then uses devalue(userInput) to prepare it for the client. devalue generates this string:

{__proto__:{isAdmin:true,vulnerable:true}}

Step 3: The Execution

This string is embedded in the HTML sent to the client, usually inside a <script> tag for hydration:

<script>
  // Hydration logic
  var data = {__proto__:{isAdmin:true,vulnerable:true}};
  // At this exact moment, Object.prototype.isAdmin becomes true globally.
</script>

Step 4: The Impact

Now, every object in the application has isAdmin: true unless specifically overridden. If the application has logic like if (user.isAdmin), and user is a plain object derived from elsewhere, the attacker has just bypassed authorization.

The Mitigation: Patch or perish

This isn't a complex buffer overflow where you need to recompile binaries. This is JavaScript. The fix is strictly logical.

Primary Mitigation: Update devalue to version 5.6.3 immediately. This version includes the fail-fast check that throws an error upon seeing __proto__.

Defense in Depth: Even with the patch, you should ask yourself why you are accepting objects with __proto__ keys from users. Consider sanitizing input at the API gateway level. If JSON.parse is your ingestion point, you can use a reviver function to nuke dangerous keys before they even reach your business logic.

JSON.parse(userInput, (key, value) => {
  if (key === '__proto__') return undefined;
  return value;
});

Do not rely on devalue to be your firewall. It is a serializer, not a WAF.

Official Patches

SvelteJS / devalueOfficial patch commit

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

Svelte applications (SSR)Nuxt.js applications (SSR)Any Node.js application using `devalue` for object serialization

Affected Versions Detail

Product
Affected Versions
Fixed Version
devalue
Rich-Harris / sveltejs
< 5.6.35.6.3
AttributeDetail
CWE IDCWE-1321
Attack VectorNetwork (Input -> Serialization -> Client Exec)
CVSS7.5 (High)
ImpactPrototype Pollution
Affected Componentdevalue npm package
Fix Commit0f04d4d678eac39ad5d7a07d1956275d7874e81c

MITRE ATT&CK Mapping

T1505Server Software Component
Persistence
T1203Exploitation for Client Execution
Execution
CWE-1321
Prototype Pollution

Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')

Known Exploits & Detection

Internal ResearchStandard Prototype Pollution vector via Object Literal evaluation

Vulnerability Timeline

Vulnerability identified and patch committed
2026-02-18
Version 5.6.3 released
2026-02-18
Advisory Published
2026-02-19

References & Sources

  • [1]Devalue Repository
  • [2]PortSwigger: Prototype Pollution Explained

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.