Jan 21, 2026·5 min read·28 visits
Seroval trusted the incoming data's claimed length (`length` or `size` properties) before actually validating the data content. By sending a tiny payload claiming to contain billions of items, an attacker can force the server to attempt a massive memory allocation, instantly crashing the Node.js process.
A resource exhaustion vulnerability in the Seroval serialization library allows attackers to trigger Out-of-Memory (OOM) crashes by supplying fake length metadata in serialized payloads.
Serialization libraries are the unsung heroes of the JavaScript ecosystem. They take your messy, circular, complex objects—Maps, Sets, BigInts—and turn them into a string that can travel over the wire. Seroval is one such library, designed to handle the edge cases that standard JSON.stringify chokes on.
But here is the golden rule of parser logic: Never trust the metadata.
Imagine you run a restaurant. A customer walks in and says, "I am ordering 5,000 pizzas," but hands you a slip of paper with nothing written on it. If your kitchen immediately starts prepping 5,000 dough balls before checking if the order actually lists any toppings, you are going to run out of flour very fast. That is exactly what Seroval was doing.
The vulnerability stems from a classic deserialization anti-pattern: Pre-allocation based on untrusted input.
In the Seroval serialized format, nodes are represented as objects. For container types like Arrays, TypedArrays, or Blobs, the format includes a metadata property—often l for length or s for size—to tell the deserializer what to expect. This is an optimization. Knowing the size upfront allows the engine to allocate the perfect amount of memory.
The problem? Seroval blindly trusted this number. It read the l property and immediately passed it to constructors like new Array(len). It didn't wait to see if the payload actually contained that many items. It just allocated the memory first, assuming the data would follow. This is a "Zip Bomb" logic flaw applied to memory allocation.
Let's look at the vulnerable logic in packages/seroval/src/core/context/deserializer.ts. Before the patch, the code looked roughly like this (simplified for clarity):
// The naive approach
const len = node.l; // Attacker says: "I have 4 billion items"
const result = new Array(len); // JS Engine: "Okay, allocating 16GB... wait, crash."
// ... populate arrayThe fix, introduced in commit ce9408ebc87312fcad345a73c172212f2a798060, applies a strict "trust but verify" model. It decouples the allocation from the metadata and enforces limits.
The Fix:
// The patched approach
const items = node.a; // The actual data provided
const len = items.length; // Calculate strict length from actual data
const result = new Array(len); // Allocate only what we hold
// Bonus: Depth Limits
if (depth > ctx.base.depthLimit) {
throw new SerovalDepthLimitError(ctx.base.depthLimit);
}The developers also added explicit guards for other heavy types, capping BigInt strings at 10,000 chars and Base64 strings at 1,000,000 chars. It's a comprehensive lockdown.
Exploiting this is trivially easy. You don't need buffer overflows or complex ROP chains. You just need a JSON editor.
An attacker constructs a serialized payload that defines an Array node. They set the items array a to be empty (or minimal), but set the length property l to the maximum integer value JavaScript can handle (e.g., $2^{32}-1$).
The Payload:
{
"t": 0,
"d": {
"t": 16, // Type: Array
"i": 0, // Reference ID
"l": 4294967295, // Length: 4.2 Billion
"a": [] // Actual content: Empty
}
}When the server parses this, it executes new Array(4294967295). Depending on the V8 engine version and available heap, this either throws a RangeError: Invalid array length immediately (if lucky) or attempts to allocate contiguous memory, triggering a hard OOM (Out of Memory) crash that kills the process instantly. If this parser is handling incoming web requests, your server is effectively dead.
This is a High Severity Denial of Service. In modern JavaScript environments—especially those using Server-Side Rendering (SSR) or handling rich data hydration—serialization libraries are often exposed to user input.
If you use Seroval to deserialize state sent from a client (e.g., in a Next.js action, a WebSocket message, or a tRPC-like setup), a single unauthenticated request can take down the worker node. In a containerized environment (Kubernetes), this leads to a crash loop. The pod dies, restarts, processes the malicious request again (if it's in a queue), and dies again.
It is the digital equivalent of pulling the fire alarm every time the teacher starts talking.
The remediation is straightforward, but you must verify your dependency tree, as Seroval might be a transitive dependency.
seroval version 1.4.1 or higher. This version includes the allocation guards and the new depth limits.depthLimit option (defaults to 1000). If your data is flat, lower this limit to 50 or 100 to further reduce attack surface against recursive stack overflow attacks.Feature.RegExp flag to disable them entirely.Don't rely on try-catch blocks to handle OOM errors; V8 often crashes the entire process before the catch block can intervene.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
lxsmnsyc/seroval lxsmnsyc | < 1.4.1 | 1.4.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-770 |
| Attack Vector | Network |
| CVSS (Est.) | 7.5 (High) |
| Impact | Availability (DoS) |
| Bug Class | Resource Exhaustion / Uncontrolled Allocation |
| Patch Commit | ce9408ebc87312fcad345a73c172212f2a798060 |
Allocation of Resources Without Limits or Throttling
A high-severity access control vulnerability in ToolHive CLI before v0.30.1 and ToolHive Studio before v0.38.0 allows local containerized MCP servers to bypass network isolation. This enables malicious workloads to establish TCP/IP connections to administrative and control plane endpoints exposed on the host loopback interface.
AnyCable is a real-time communication server. Prior to version 1.6.15, its Pusher-compatible REST API suffered from an authentication bypass vulnerability because it failed to verify that the request body matched the signature-validated body_md5 parameter. This allows attackers to perform replay attacks with modified body contents.
A denial-of-service vulnerability exists in AnyIO prior to version 4.14.2. Standard error streams of process-pool workers are connected to an operating system pipe that is never drained by the parent process. This allows a worker to fill the pipe buffer and deadlock indefinitely.
CVE-2026-63349 is a critical privilege-dropping bypass vulnerability in the AnyIO asynchronous framework (versions 4.14.0 and 4.14.1) on POSIX platforms. Due to a variable assignment typo, supplementary groups specified by the developer are not correctly propagated to the execution backend, resulting in subprocesses retaining the parent process's elevated supplementary group permissions.
CVE-2026-63406 is an information disclosure vulnerability in AnyCable-go prior to version 1.6.15. The built-in telemetry client is enabled by default with a hardcoded public authentication token ('secret'). This client digests highly sensitive configuration parameters and command-line arguments, including JWT secrets and RPC secrets, into a stable SHA-256 fingerprint. This fingerprint is sent over public networks, exposing those administrative secrets to offline dictionary and brute-force attacks if intercepted.
CVE-2026-84992 is a Cross-Site Scripting (XSS) vulnerability affecting md-editor-v3 before version 6.5.4. It occurs because the fenced-code block language parser directly interpolates unescaped language metadata into unquoted HTML attributes inside the custom rendering callback. This bypasses the built-in XSSPlugin which runs during the parsing phase, before rendering.