Back to Blog
high SEVERITY8 min read

How Denial of Service happens in Node.js devalue and how to fix it

A high-severity Denial of Service vulnerability (CVE-2026-22774) was discovered in the `devalue` package used by the exo-dashboard SvelteKit application. Attackers could craft malicious input to trigger excessive resource consumption in the devalue deserialization library, potentially taking down the web service. The fix upgrades `devalue` from version 5.5.0 to 5.6.2 in both `package.json` and `package-lock.json`.

O
By Orbis AppSec
Published June 25, 2026Reviewed June 25, 2026

Answer Summary

CVE-2026-22774 is a Denial of Service vulnerability (CWE-400) in the `devalue` npm package versions prior to 5.6.2, affecting Node.js/SvelteKit applications. When untrusted input is passed to devalue's deserialization routines, an attacker can trigger excessive resource consumption — CPU or memory exhaustion — causing the service to become unresponsive. The fix is to upgrade `devalue` from 5.5.0 to 5.6.2 by updating both `package.json` (adding `"devalue": "^5.6.2"` to dependencies) and regenerating `package-lock.json` to pin the patched version.

Vulnerability at a Glance

cweCWE-400 (Uncontrolled Resource Consumption)
fixUpgrade devalue dependency from 5.5.0 to 5.6.2 in package.json and package-lock.json
riskRemote attacker can exhaust server resources and crash or hang the web service
languageJavaScript / Node.js (SvelteKit)
root causedevalue 5.5.0 does not adequately bound resource usage when deserializing attacker-controlled input
vulnerabilityDenial of Service via excessive resource consumption (CVE-2026-22774)

How Denial of Service happens in Node.js devalue and how to fix it

Summary

A high-severity Denial of Service vulnerability (CVE-2026-22774) was discovered in the devalue package used by the exo-dashboard SvelteKit application. Attackers could craft malicious serialized input to trigger excessive resource consumption, potentially rendering the web service unresponsive. The fix upgrades devalue from version 5.5.0 to 5.6.2 across both dashboard/package.json and dashboard/package-lock.json.


Introduction

The exo-dashboard is a SvelteKit-based web application that handles user-facing requests in a production environment. Inside its dependency tree sits devalue — a library designed to serialize and deserialize rich JavaScript values (including things like Map, Set, Date, and circular references) that JSON alone can't handle. It's commonly used in SvelteKit's server-side data loading pipeline.

The problem: devalue version 5.5.0 does not adequately constrain how much work it performs when processing untrusted input. An attacker who can influence the serialized data flowing into devalue's deserialization routines — for example, through a crafted HTTP request body or a malicious server response — can trigger runaway resource consumption. On a web service exposed to the internet, this translates directly to a remotely exploitable Denial of Service.

Trivy's dependency scanner flagged this in dashboard/package-lock.json, where the pinned version 5.5.0 was identified as vulnerable under rule CVE-2026-22774.


The Vulnerability Explained

What is devalue, and where does it run?

devalue is not just a development tool — in SvelteKit applications, it is used at runtime to serialize data returned from load() functions on the server and deserialize it on the client. This means it processes data that can be influenced by external actors: API responses, database content, and in some configurations, direct user input.

The vulnerable version

The vulnerable entry in dashboard/package-lock.json before the fix looked like this:

"node_modules/devalue": {
    "version": "5.5.0",
    "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.5.0.tgz",
    "integrity": "sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==",
    "license": "MIT"
}

In devalue 5.5.0, the deserialization logic does not impose strict limits on the complexity or depth of the input it processes. An attacker can construct a deeply nested or cyclically referenced serialized payload that forces devalue to recurse excessively or allocate unbounded memory while attempting to reconstruct the JavaScript object graph.

A concrete attack scenario

Consider a SvelteKit route that accepts serialized data from a client or an upstream API and passes it through devalue for deserialization. An attacker sends a payload like a deeply nested array structure:

// Pseudocode representation of a malicious devalue payload
["BigArray", [["BigArray", [["BigArray", [...10,000 levels deep...]]]]]]

When devalue 5.5.0 attempts to walk this structure to reconstruct the JavaScript value, it may:

  1. Exhaust the call stack through unbounded recursion
  2. Spike CPU usage as it traverses exponentially complex reference graphs
  3. Consume heap memory allocating intermediate objects for each level

In a Node.js web server handling concurrent requests, a single such request can degrade response times for all users. A sustained stream of such requests can take the service entirely offline — no authentication required.

Why this matters for exo-dashboard specifically

The exo-dashboard is described as a web service where "vulnerabilities in request handlers are directly exploitable by remote attackers." The devalue package is listed as a production dependency (not a devDependency), meaning it is active in the deployed application, not just during the build process. This removes any argument that the vulnerability is theoretical or limited to development environments.


The Fix

What changed

The fix involved two files: dashboard/package.json and dashboard/package-lock.json.

dashboard/package.json — Adding an explicit production dependency:

 "dependencies": {
+    "devalue": "^5.6.2",
     "highlight.js": "^11.11.1",
     "katex": "^0.16.27",
     "marked": "^17.0.1",

Previously, devalue was only pulled in transitively (as a dependency of SvelteKit internals) without being explicitly declared in package.json. Adding it explicitly with "^5.6.2" ensures that npm's resolver will always select a patched version, even if a transitive dependency would otherwise resolve to the vulnerable 5.5.0.

dashboard/package-lock.json — Pinning the patched version:

 "node_modules/devalue": {
-    "version": "5.5.0",
-    "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.5.0.tgz",
-    "integrity": "sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==",
+    "version": "5.6.2",
+    "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.2.tgz",
+    "integrity": "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==",
     "license": "MIT"
 }

The lock file update is critical. Without it, npm ci (used in most CI/CD pipelines) would continue installing the vulnerable 5.5.0 regardless of what package.json says, because npm ci respects the lock file exactly. Updating the lock file ensures reproducible, secure installs across all environments.

How the fix works

devalue 5.6.2 introduces internal safeguards that bound the complexity of the input it will process. This includes limits on recursion depth and the total number of nodes it will traverse when reconstructing a JavaScript value from a serialized payload. Inputs that exceed these bounds are rejected with an error rather than being processed indefinitely.

The integrity hash change (sha512-69sM5...sha512-nPRkj...) confirms that a genuinely different package artifact is being installed — this is not just a metadata change.


Prevention & Best Practices

1. Declare all runtime dependencies explicitly

Even if a package is pulled in transitively, if your application depends on it at runtime, declare it explicitly in dependencies. This gives you control over the version range and makes security upgrades straightforward.

2. Never pass untrusted input directly to deserialization libraries

Deserialization is a high-risk operation. Before passing any external data to libraries like devalue, JSON.parse with revivers, or similar, validate its structure and size:

// Example: reject oversized payloads before deserialization
app.use(express.json({ limit: '10kb' }));

// Or validate structure with a schema library like zod
import { z } from 'zod';
const schema = z.string().max(1000);
const safeInput = schema.parse(rawInput);

3. Scan your lock files in CI

Tools like Trivy, npm audit, and Snyk can scan package-lock.json for known-vulnerable versions. Add these scans as required checks in your CI pipeline so vulnerable dependencies are caught before they reach production:

# Run Trivy on the dashboard directory
trivy fs ./dashboard --exit-code 1 --severity HIGH,CRITICAL

4. Use npm audit regularly

cd dashboard && npm audit

This will surface known CVEs in your dependency tree and suggest upgrade paths. Automate this in your development workflow.

5. Understand the difference between dependencies and devDependencies

Libraries used at runtime (like devalue in a SvelteKit app) belong in dependencies. Scanners and security tools treat these differently — production dependencies get higher scrutiny because they are present in deployed environments.

Security Standards References

  • CWE-400: Uncontrolled Resource Consumption — the root cause category for this vulnerability
  • OWASP A05:2021 — Security Misconfiguration: includes failing to update components with known vulnerabilities
  • OWASP A06:2021 — Vulnerable and Outdated Components: directly applicable to this dependency upgrade scenario

Key Takeaways

  • devalue 5.5.0 is vulnerable in production SvelteKit apps: If your package-lock.json pins devalue at 5.5.0, you are exposed to CVE-2026-22774 in any environment where user-influenced data reaches the deserialization path.
  • Transitive dependencies need explicit pinning: devalue was not originally declared in package.json, meaning its version was controlled entirely by SvelteKit's own dependency range. Adding an explicit "devalue": "^5.6.2" entry takes back control.
  • Lock file updates are not optional: Changing package.json alone is insufficient. The package-lock.json must be regenerated and committed to ensure npm ci installs the patched version in CI/CD and production.
  • Trivy caught what a code review would miss: The vulnerability was not in application code — it was in a pinned version number inside a lock file. Automated dependency scanning is the only reliable way to catch this class of issue.
  • Production dependency classification matters: Because devalue is in dependencies (not devDependencies), it is present in the deployed exo-dashboard service, making this a directly exploitable remote attack surface.

How Orbis AppSec Detected This

  • Source: Untrusted data (user-influenced HTTP request bodies or external API responses) flowing into SvelteKit's data loading pipeline
  • Sink: devalue's deserialization routines in node_modules/devalue version 5.5.0, invoked at runtime within the exo-dashboard web service
  • Missing control: No version constraint preventing the installation of the vulnerable 5.5.0 artifact; no input size or complexity bounds in the devalue library itself at that version
  • CWE: CWE-400 — Uncontrolled Resource Consumption
  • Fix: Upgraded devalue from 5.5.0 to 5.6.2 in both dashboard/package.json and dashboard/package-lock.json, pinning the patched artifact with its verified integrity hash

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

CVE-2026-22774 is a reminder that security vulnerabilities don't only live in the code you write — they live in the versions of libraries you depend on. The exo-dashboard application was exposed to a remotely exploitable Denial of Service simply because devalue 5.5.0 was pinned in its lock file without an explicit version constraint in package.json.

The fix is precise and minimal: two files changed, one version number bumped, and the attack surface is closed. But getting there required knowing the vulnerability existed in the first place — which is exactly the gap that automated dependency scanning fills.

If your Node.js or SvelteKit application uses devalue, check your package-lock.json now. If you see any version below 5.6.2, you are vulnerable.


References

Frequently Asked Questions

What is CVE-2026-22774?

CVE-2026-22774 is a high-severity Denial of Service vulnerability in the devalue npm package (versions before 5.6.2) where processing untrusted serialized input can cause excessive CPU or memory consumption, crashing the server.

How do you prevent Denial of Service from devalue in Node.js?

Upgrade devalue to version 5.6.2 or later, which introduces input bounds checking. Additionally, validate and sanitize all user-supplied data before passing it to deserialization functions.

What CWE is this Denial of Service vulnerability?

CWE-400 — Uncontrolled Resource Consumption ("Resource Exhaustion"), which covers cases where an application does not properly limit the resources it allocates in response to untrusted input.

Is input validation alone enough to prevent this devalue DoS?

Input validation helps reduce the attack surface, but the root fix is upgrading to devalue 5.6.2, which patches the internal resource bounding logic. Relying only on upstream validation without patching the library leaves the vulnerability open.

Can static analysis detect this devalue vulnerability?

Yes — tools like Trivy (which flagged this exact issue) scan dependency lock files for known-vulnerable package versions and will report CVE-2026-22774 when devalue < 5.6.2 is detected in package-lock.json.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #2150

Related Articles

high

How Client-Side Denial of Service Happens in Node.js FTP Clients and How to Fix It

CVE-2026-44240 is a client-side denial of service vulnerability in the basic-ftp Node.js library that allows attackers to crash FTP clients by sending malformed, unterminated multiline FTP responses. Upgrading from version 5.0.5 to 5.3.1 patches this critical flaw that could have disrupted any application using the vulnerable library for FTP operations.

high

How Quadratic-Complexity DoS via mailto: Validator happens in linkify-it and how to fix it

A high-severity algorithmic complexity vulnerability (CVE-2026-59887) was discovered in linkify-it 5.0.1, where the mailto: validator's scan-loop exhibited quadratic time complexity when processing attacker-controlled text. This vulnerability could allow attackers to cause denial-of-service conditions by submitting specially crafted input that triggers excessive processing time. The fix involved upgrading linkify-it from version 5.0.1 to 5.0.2 in the tizumark project.

high

How unvalidated PUT_VALUE records happen in Node.js @libp2p/kad-dht and how to fix it

CVE-2026-45783 is a high-severity vulnerability in `@libp2p/kad-dht` versions prior to 16.2.6 where DHT server nodes accept and store PUT_VALUE records without validating their content or enforcing storage limits, allowing any peer on the network to exhaust disk space. The fix upgrades the package from 16.1.3 to 16.2.6, which introduces proper record validation before writes are committed to disk. Developers building decentralized applications on libp2p are directly affected if they run DHT serv

high

How exponential-time complexity denial of service happens in brace-expansion and how to fix it

CVE-2026-13149 is a denial of service vulnerability in the brace-expansion library that allows attackers to craft specially-formatted input strings that trigger exponential-time complexity in the expansion algorithm. This fix upgrades brace-expansion from version 1.1.15 to 1.1.16, eliminating the algorithmic flaw that could freeze applications processing untrusted input patterns.

high

How Denial of Service via excessive memory allocation happens in Node.js adm-zip and how to fix it

A high-severity Denial of Service vulnerability (CVE-2026-39244) was discovered in adm-zip versions prior to 0.6.0, affecting the laliga-fantasy-app. Attackers could craft malicious ZIP files that trigger excessive memory allocation, potentially crashing the web service. The fix involved upgrading adm-zip from version 0.5.16 to 0.6.0, which includes proper memory allocation bounds checking.

high

How Memory Exhaustion via Large Comma-Separated Selector Lists happens in Python Soup Sieve and how to fix it

A high-severity memory exhaustion vulnerability (CVE-2026-49476) was discovered in Soup Sieve version 2.8.3, affecting Python applications that parse CSS selectors from user-controlled input. The vulnerability allows attackers to craft malicious selector lists that consume excessive memory, potentially causing denial of service. The fix involves upgrading to soupsieve 2.8.4, which implements proper resource limits on selector parsing.