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 Quadratic CPU Consumption Vulnerabilities Happen in JavaScript YAML Parsers and How to Fix Them

A high-severity denial-of-service vulnerability in js-yaml versions 3.x and 4.x allowed attackers to trigger quadratic CPU consumption through specially crafted YAML documents using the !!omap tag. This fix upgrades js-yaml from 4.1.1 to 4.3.1 and from 3.14.2 to 3.15.1, eliminating the algorithmic complexity attack vector that could freeze Node.js applications processing untrusted YAML input.

high

How Email Exhaustion Denial of Service Happens in Node.js OTP Endpoints and How to Fix It

A Node.js authentication service exposed unauthenticated OTP endpoints without adequate rate limiting, allowing attackers to exhaust email service quotas through repeated requests. The fix implements per-session resend caps and cooldown enforcement to prevent email-based denial of service attacks while preserving legitimate user workflows.

high

How Unauthenticated Denial of Service happens in React Router and how to fix it

CVE-2026-55685 is a high-severity Denial of Service vulnerability in React Router's `@remix-run/server-runtime` that allows unauthenticated attackers to exhaust server resources by sending crafted requests to the manifest endpoint. The fix upgrades `react-router` from version 7.17.0 to 7.18.0, which tightens handling of untrusted input in route matching logic. Developers using any React Router 7.x application with server-side rendering should apply this patch immediately.

high

How Quadratic CPU Consumption in YAML Parsing happens in JavaScript and how to fix it

A high-severity vulnerability in js-yaml versions 3.x and 4.x allowed attackers to cause quadratic CPU consumption through specially crafted YAML documents using the `!!omap` type. This denial-of-service vulnerability (GHSA-5p4m-2wfm-xmqj) was fixed by upgrading from js-yaml 4.3.0 to 4.3.1, protecting applications from algorithmic complexity attacks during YAML parsing.

high

How Infinite Loop Denial of Service happens in nanoid custom alphabet generation and how to fix it

A high-severity infinite loop vulnerability (CVE-2026-67213) was discovered in nanoid versions before 5.1.6 and 3.3.17, affecting the custom alphabet generation feature. When processing certain malformed alphabet configurations, nanoid would enter an infinite loop, causing a complete denial of service. This vulnerability was fixed by upgrading from nanoid 3.3.16 to 3.3.17 and implementing dependency overrides to ensure the patched version is used throughout the dependency tree.

high

How Quadratic CPU Consumption in !!omap Resolution Happens in js-yaml and How to Fix It

A high-severity denial-of-service vulnerability in js-yaml (GHSA-5p4m-2wfm-xmqj) caused quadratic CPU consumption when resolving `!!omap` (ordered map) YAML tags, affecting both the 3.x and 4.x release lines. Upgrading to js-yaml 4.3.1 or 3.15.1 closes the gap by fixing the algorithmic inefficiency in `!!omap` duplicate-key detection. Any application that parses untrusted YAML input is at risk of resource exhaustion leading to service unavailability.