CVE-2026-23957

Death by Allocation: Crashing Seroval with a Single Byte

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 21, 2026·5 min read·2 visits

Executive Summary (TL;DR)

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.

The Hook: Serial Killers

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 Flaw: Trust Issues

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.

The Code: The Smoking Gun

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 array

The 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.

The Exploit: Dropping the Bomb

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.

The Impact: Why Panic?

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 Mitigation: Stop the Bleeding

The remediation is straightforward, but you must verify your dependency tree, as Seroval might be a transitive dependency.

  1. Upgrade Immediately: Move to seroval version 1.4.1 or higher. This version includes the allocation guards and the new depth limits.
  2. Configure Limits: The new version introduces a 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.
  3. Disable Unused Features: If you don't need to deserialize Regular Expressions (which can also be used for ReDoS), use the new 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.

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:N/A:H

Affected Systems

Node.js Applications using SerovalFull-stack JS Frameworks (SSR)Data Hydration Systems

Affected Versions Detail

Product
Affected Versions
Fixed Version
lxsmnsyc/seroval
lxsmnsyc
< 1.4.11.4.1
AttributeDetail
CWE IDCWE-770
Attack VectorNetwork
CVSS (Est.)7.5 (High)
ImpactAvailability (DoS)
Bug ClassResource Exhaustion / Uncontrolled Allocation
Patch Commitce9408ebc87312fcad345a73c172212f2a798060
CWE-770
Allocation of Resources Without Limits or Throttling

Allocation of Resources Without Limits or Throttling

Vulnerability Timeline

Fix commit ce9408e pushed to main
2026-01-21
Version 1.4.1 released
2026-01-21
Version 1.4.2 released
2026-01-21

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.