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



CVE-2026-116584

CVE-2026-116584: Denial of Service via Unvalidated Node Element Lists in Seroval

Amit Schendel
Amit Schendel
Senior Security Researcher

Oct 29, 2026·10 min read·3 visits

Executive Summary (TL;DR)

Seroval versions >= 1.4.1 and < 1.6.8 are vulnerable to Denial of Service in fromJSON and fromCrossJSON because node element lists are not validated with Array.isArray(), allowing attackers to pass counterfeit objects like {"length": 2000000} to trigger excessive memory allocation and CPU exhaustion.

A Denial of Service (DoS) vulnerability exists in the Seroval JavaScript serialization library affecting versions 1.4.1 through 1.6.7. The deserialization routines fromJSON and fromCrossJSON fail to verify that node element lists are actual JavaScript Array primitives before reading their length property. An unauthenticated remote attacker can supply a compact, malformed JSON payload containing an array-like object with an arbitrary length value, causing unbounded memory allocation and synchronous loop iterations that block the event loop or crash the process via heap exhaustion.

Vulnerability Overview

Seroval is a JavaScript library designed to serialize and deserialize complex data structures that standard JSON.stringify and JSON.parse cannot represent. These structures include circular references, Set, Map, BigInt, Promise, ReadableStream, and custom iterable sequences. It is commonly integrated into full-stack JavaScript and TypeScript meta-frameworks—such as SolidStart, Qwik, SvelteKit, and Vinxi—to handle Remote Procedure Call (RPC) payloads, server actions, and SSR state hydration across network boundaries.

In Seroval versions >= 1.4.1 and < 1.6.8, the JSON deserialization entry points fromJSON and fromCrossJSON contain an input validation flaw classified under CWE-770 (Allocation of Resources Without Limits or Throttling). When reconstructing composite data types from a serialized Abstract Syntax Tree (AST), the deserializer expects internal node properties that hold child elements or key-value pairs to be JavaScript arrays. However, the parser does not verify the structural type of these properties before accessing their .length attribute.

Because the input to fromJSON and fromCrossJSON is typically derived from untrusted JSON parsed over an HTTP request or WebSocket connection, an attacker can substitute expected array structures with plain JSON objects containing an arbitrary length property (e.g., {"length": 20000000}). The deserializer trusts this attacker-controlled integer to pre-allocate target arrays and govern synchronous for loop bounds.

This vulnerability represents a residual bypass of the fix implemented for CVE-2026-23957. While prior patches introduced reference validation and boundary checks, they relied on the implicit assumption that collection fields on AST nodes were genuine arrays whose length corresponded to physical elements transmitted over the wire. By bypassing physical payload size constraints, a sub-100-byte request can force a Node.js or edge runtime process to exhaust its V8 heap memory or lock the single-threaded event loop indefinitely.

Root Cause Analysis

To serialize complex JavaScript objects into JSON-compatible formats, Seroval converts values into a tree of typed AST nodes (SerovalNode). Each node is represented as a plain object containing metadata tags—such as t for node type and i for reference ID—alongside type-specific data fields. For collection and composite types, child elements are stored in dedicated list properties: node.a for Array, Set, StreamConstructor, and Sequence nodes; node.k and node.v for object record properties; and node.e.k and node.e.v for Map entries.

During normal operation, toJSON and toCrossJSON populate these properties with standard JavaScript arrays. Consequently, the number of elements in node.a or node.k is strictly proportional to the serialized byte length of the JSON payload. When fromJSON or fromCrossJSON is invoked, the deserializer traverses this AST recursively, dispatching each node to a specialized handler function inside packages/seroval/src/core/context/deserializer.ts based on its type identifier node.t.

The root cause of CVE-2026-116584 is that six distinct deserialization handlers—deserializeArray, deserializeProperties, deserializeSet, deserializeMap, deserializeStreamConstructor, and deserializeSequence—accessed .length and indexed elements (items[i]) on these collection properties without calling Array.isArray(). In JavaScript, property access is duck-typed; reading .length on a plain object {"length": 2000000} evaluates to the number 2000000, while accessing non-existent numeric indices like items[0] simply returns undefined without throwing a runtime exception.

When deserializeArray processes a tampered node where node.a is {"length": 2000000}, it immediately invokes new Array(2000000) to allocate a sparse array of two million slots, and then executes a tight synchronous for loop two million times. On each iteration, items[i] evaluates to undefined, which is passed into deserialize(ctx, depth, undefined). This mismatch decouples algorithmic complexity and memory allocation from the physical wire size of the input, allowing arbitrary resource amplification.

Code Analysis

The vulnerability is located in packages/seroval/src/core/context/deserializer.ts. Prior to version 1.6.8, the deserialization functions operated directly on the unvalidated properties of the input AST node. In deserializeArray, node.a was assigned to items, and items.length was immediately used to allocate memory and control loop execution:

// Vulnerable implementation in packages/seroval/src/core/context/deserializer.ts
function deserializeArray(
  ctx: DeserializerContext,
  depth: number,
  node: SerovalArrayNode,
): unknown[] {
  const items = node.a;
  const len = items.length; // Unvalidated read: accepts { length: N }
  const result: unknown[] = assignIndexedValue(
    ctx,
    node.i,
    new Array(len), // Pre-allocates array based on untrusted length
  );
  for (let i = 0; i < len; i++) {
    // Iterates 'len' times even if 'items' has no actual elements
    result[i] = deserialize(ctx, depth, items[i]);
  }
  return result;
}

Identical patterns existed in deserializeProperties (reading node.k.length and indexing node.v[i]), deserializeSet (reading node.a.length), deserializeMap (reading node.e.k.length and indexing node.e.v[i]), deserializeStreamConstructor (reading node.a.length), and deserializeSequence (reading node.a.length). Note that in deserializeProperties and deserializeMap, even if the keys list k was a valid array, replacing the values list v with a non-array could also lead to malformed state reconstruction.

In commit cdcee3e3bc384ee844360844f8ea98fd2b275d69, the maintainer introduced a helper function named validateNodeList that enforces strict Array.isArray() verification before any length read or iteration occurs. If the check fails, the deserializer immediately aborts execution by throwing a SerovalMalformedNodeError:

// Patched implementation in packages/seroval/src/core/context/deserializer.ts
function validateNodeList(
  node: SerovalNode | SerovalObjectRecordNode,
  list: unknown,
): void {
  if (!Array.isArray(list)) {
    throw new SerovalMalformedNodeError(node as SerovalNode);
  }
}
 
function deserializeArray(
  ctx: DeserializerContext,
  depth: number,
  node: SerovalArrayNode,
): unknown[] {
  const items = node.a;
  validateNodeList(node, items); // Ensures 'items' is a genuine Array
  const len = items.length;
  const result: unknown[] = assignIndexedValue(
    ctx,
    node.i,
    new Array(len),
  );
  for (let i = 0; i < len; i++) {
    result[i] = deserialize(ctx, depth, items[i]);
  }
  return result;
}

The patch applies validateNodeList across all six affected functions, including dual checks on both node.k and node.v in deserializeProperties, and both node.e.k and node.e.v in deserializeMap. This fix is complete with respect to array-like object spoofing: because Array.isArray() only returns true for genuine JavaScript Array instances created by JSON.parse (when parsing [...]), the .length property is guaranteed to match the exact number of elements physically present in the JSON payload. However, one minor observation in deserializeProperties and deserializeMap is that while both k and v are validated as arrays, their lengths are not explicitly checked for equality (k.length === v.length), though any discrepancy remains bounded by the physical payload size.

Exploitation

Exploiting CVE-2026-116584 requires an application endpoint that accepts untrusted JSON input and passes the parsed object into fromJSON() or fromCrossJSON(). No authentication or special privileges are required if the deserialization endpoint is publicly reachable (such as a public RPC handler or server function endpoint). The attacker does not need to control the surrounding application logic; triggering the deserialization step alone is sufficient.

To construct an exploit payload, an attacker first generates a valid serialized AST using toJSON() or toCrossJSON() for any supported composite type—such as a single-element array [1], a Set, or a Map—and then modifies the serialized JSON to replace the array property with an object defining length. The official test suite in packages/seroval/test/malformed-node-list.test.ts demonstrates how these payloads are structured across multiple node types:

import { fromCrossJSON, fromJSON, toCrossJSON, toJSON } from 'seroval';
 
// 1. Exploit via fromJSON Array node
const arrayPayload = toJSON([1]);
// Replace genuine array 'a' with an array-like object
(arrayPayload.t as unknown as { a: unknown }).a = { length: 2_000_000 };
fromJSON(arrayPayload); // Triggers unbounded allocation and loop in < 1.6.8
 
// 2. Exploit via fromCrossJSON Array node
const crossPayload = toCrossJSON([1]);
(crossPayload as unknown as { a: unknown }).a = { length: 2_000_000 };
fromCrossJSON(crossPayload, { refs: new Map() });
 
// 3. Exploit via Set node
const setPayload = toJSON(new Set([1]));
(setPayload.t as unknown as { a: unknown }).a = { length: 2_000_000 };
fromJSON(setPayload);
 
// 4. Exploit via Map node entry keys
const mapPayload = toJSON(new Map([[1, 2]]));
(mapPayload.t as unknown as { e: { k: unknown } }).e.k = { length: 2_000_000 };
fromJSON(mapPayload);

Depending on the value assigned to length, the attacker can achieve different failure modes:

  • Event Loop Starvation (CPU Exhaustion): Setting length to a moderately large integer (e.g., 10_000_000 to 100_000_000) forces the single-threaded JavaScript runtime into a prolonged synchronous loop. During this window, the server cannot process health checks, handle concurrent HTTP requests, or execute I/O callbacks.
  • Process Crash via Out-Of-Memory (OOM): Setting length to a value near the V8 array limit (or sending multiple concurrent requests with length: 50_000_000) forces rapid heap allocations in new Array(len), Set.prototype.add, or Map.prototype.set. This exhausts the Node.js heap limit and terminates the worker or process with FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory.
  • Unhandled Exceptions: Passing non-standard length values such as {"length": "Infinity"}, {"length": -1}, or {"length": 1.5} causes new Array(len) in deserializeArray to throw an unhandled RangeError: Invalid array length, potentially crashing processes that only catch SerovalError subclasses.

Impact Assessment

CVE-2026-116584 is rated High severity with a CVSS v3.1 base score of 7.5 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H). The vulnerability affects availability exclusively, with no direct impact on confidentiality or data integrity. Because JavaScript runtimes like Node.js, Deno, and Bun execute user-space JavaScript on a single main event loop thread per process, synchronous CPU-bound loops or fatal V8 heap OOM errors affect all concurrent users sharing that process instance.

The primary operational risk stems from the asymmetry between request size and server workload. Many web application firewalls (WAFs), reverse proxies (such as Nginx or Cloudflare), and body-parsing middleware rely on HTTP Content-Length limits (e.g., 100 KB or 1 MB) to prevent resource exhaustion during JSON parsing. Because a malicious Seroval payload requires less than 100 bytes on the wire to specify a length of 1e9, size-based rate limiting and body-size restrictions are completely ineffective against this attack vector.

> [!NOTE] > As of October 2026, the FIRST Exploit Prediction Scoring System (EPSS) assigns this vulnerability a score of 0.00365 (0.36%, 30.19th percentile), and it is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. However, functional proof-of-concept payloads are publicly available within the vendor's unit test suite.

Applications at highest risk are those utilizing full-stack frameworks or custom RPC bridges that expose Seroval deserialization directly to client-controlled HTTP POST bodies or WebSocket frames. In containerized or serverless deployments, repeated exploitation can trigger cascading container restarts, autoscaling exhaustion, or denial of service across shared worker pools.

Remediation

The definitive remediation is to upgrade seroval (and any co-installed seroval-plugins packages) to version 1.6.8 or later. Version 1.6.8 incorporates commit cdcee3e3bc384ee844360844f8ea98fd2b275d69, which enforces Array.isArray() validation across all deserialization node handlers and throws a SerovalMalformedNodeError when encountering counterfeit array-like objects.

Developers should update their dependencies using their respective package manager and verify that transitive dependencies resolved by meta-frameworks (such as SolidStart, Vinxi, or Qwik) are also updated in the lockfile:

# Using npm
npm install seroval@^1.6.8
 
# Using pnpm
pnpm update seroval --latest
 
# Using yarn
yarn upgrade seroval@^1.6.8

If seroval is pulled in strictly as a transitive dependency of an upstream framework that has not yet bumped its dependency range, use package manager overrides (overrides in package.json for npm/pnpm, or resolutions for Yarn) to force resolution to >=1.6.8:

{
  "overrides": {
    "seroval": "^1.6.8"
  }
}

For environments where an immediate package upgrade is not feasible, implement pre-deserialization schema validation on parsed JSON ASTs before invoking fromJSON or fromCrossJSON. A recursive validator should inspect every object in the parsed JSON payload and reject any payload where properties .a, .k, .v, .e.k, or .e.v are defined as non-array objects (i.e., typeof val === 'object' && val !== null && !Array.isArray(val)). Additionally, ensure that application error handlers surrounding fromJSON catch both SerovalMalformedNodeError and standard JavaScript RangeError exceptions gracefully without crashing the host process.

Official Patches

lxsmnsycOfficial patch commit adding validateNodeList to Seroval deserializer
lxsmnsycSeroval v1.6.8 release containing the fix for CVE-2026-116584
GitHubGitHub Security Advisory GHSA-wp97-x4hv-qvhp

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
EPSS Probability
0.36%
Top 70% most exploited

Affected Systems

serovalseroval-plugins

Affected Versions Detail

Product
Affected Versions
Fixed Version
seroval
lxsmnsyc
>= 1.4.1, < 1.6.81.6.8
AttributeDetail
CVE IDCVE-2026-116584 (GHSA-wp97-x4hv-qvhp)
Weakness ClassCWE-770: Allocation of Resources Without Limits or Throttling
Attack VectorNetwork (Unauthenticated JSON Deserialization)
CVSS v3.1 Score7.5 High (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)
EPSS Score0.36% (30.19th Percentile)
ImpactDenial of Service (V8 Heap OOM & Event Loop Starvation)
Exploit StatusPoC Available (Unit tests in official patch)
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
CWE-770
Allocation of Resources Without Limits or Throttling

The software allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor.

Vulnerability Timeline

Fix commit cdcee3e3bc384ee844360844f8ea98fd2b275d69 authored and merged into the Seroval repository.
2026-09-28
GitHub Security Advisory GHSA-wp97-x4hv-qvhp and CVE-2026-116584 published to NVD.
2026-10-26
OSV database updated with affected version ranges and EPSS score initialized.
2026-10-28

References & Sources

  • [1]GitHub Security Advisory: GHSA-wp97-x4hv-qvhp
  • [2]Seroval Fix Commit: validate node element lists during deserialization
  • [3]Seroval Release v1.6.8
  • [4]NVD - CVE-2026-116584 Detail
  • [5]CVE.org Record: CVE-2026-116584
  • [6]CVEListV5 JSON Record for CVE-2026-116584
Related Vulnerabilities
CVE-2026-23957

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.

More Reports

•less than a minute ago•CVE-2026-115910
6.8

CVE-2026-115910: OpenID Connect Session-Binding Bypass and Account Takeover in Python Social Auth

A session-binding vulnerability in Python Social Auth (social-core) versions prior to 6.2.0 allows an attacker to perform authorization code injection against the OpenID Connect authentication backend. By storing generated OIDC nonces in a global database table without binding them to the initiating browser session, the library accepts any valid, unexpired nonce returned in an ID token regardless of which session originated the authentication transaction. When combined with the default disablement of Proof Key for Code Exchange (PKCE), an attacker who intercepts an unused authorization code can inject it into their own authentication flow to achieve full account takeover.

Amit Schendel
Amit Schendel
0 views•13 min read
•30 minutes ago•CVE-2026-111497
9.8

CVE-2026-111497: Out-of-Bounds Heap Write and Remote Code Execution in Google Brotli Decoder (Node2Shell)

CVE-2026-111497, tracked in threat intelligence under the aliases Node2Shell, Broccoli2Shell, and HTTP2Shell, is a critical out-of-bounds heap write and denial-of-service vulnerability in the reference Google Brotli decompression library (c/dec/decode.c). The flaw originates from an unchecked return value and error-code conflation in DecodeBlockTypeAndLength() when processing malformed streams with single-block-type declarations (max_block_type <= 1). On the fast decoding path, the ignored error return causes the 32-bit unsigned block_length counter to underflow from 0 to UINT32_MAX (0xFFFFFFFF), corrupting internal decoder tables and enabling arbitrary heap memory overwrites via memmove16(). On the streaming path, the error return is misinterpreted as an incomplete bit-stream, trapping the worker process in an infinite 100% CPU loop. Because Google Brotli is embedded across major runtimes and infrastructure components—including Node.js, Envoy Proxy, Microsoft .NET, Istio, and Python—the vulnerability exposes a broad attack surface via standard HTTP Content-Encoding: br request and response bodies.

Amit Schendel
Amit Schendel
2 views•12 min read
•about 1 hour ago•CVE-2026-116575
6.3

CVE-2026-116575: Cross-Tenant Conversation Disclosure via Delimiter Injection in Mem0

CVE-2026-116575 (GHSA-5324-3w58-qpp2) is an unescaped delimiter injection and canonicalization flaw in the Mem0 persistent memory platform for AI agents and applications. Prior to Python SDK version 2.0.18 and TypeScript SDK version 3.1.6, the session scope key construction functions join caller-controlled user_id, agent_id, and run_id identifiers using raw '=' and '&' delimiters without sanitization. An attacker who controls one of these identifiers in a multi-tenant deployment can inject delimiter sequences to force a string collision with a target tenant's session scope key, resulting in unauthorized disclosure, poisoning, or eviction of the target tenant's recent conversation buffer.

Alon Barad
Alon Barad
2 views•9 min read
•about 2 hours ago•CVE-2026-116580
7.3

CVE-2026-116580: Unvalidated Method Invocation via Identifier Reuse in Seroval Deserializer

Seroval versions prior to 1.6.8 contain an insecure deserialization vulnerability (CWE-502) in the `fromJSON` parser. When reconstructing `AsyncIteratorFactoryInstance` or `IteratorFactoryInstance` nodes, the deserializer verifies the source node type using its identifier in the AST lookup table rather than verifying the runtime identity of the deserialized object. Because unmarked node identifiers omitted from the `m` reference array can be reused in vanilla deserialization mode, an attacker can substitute an arbitrary plain object or plugin-produced value as the stream source. This causes the runtime to invoke `.on(listener)` on an attacker-controlled target.

Amit Schendel
Amit Schendel
2 views•12 min read
•about 4 hours ago•CVE-2026-116581
7.5

CVE-2026-116581: Unauthenticated Event-Loop Denial of Service via Unvalidated Sequence Indices in Seroval

Seroval, a JavaScript serialization library used for transferring complex structures across network boundaries, contains an input validation vulnerability in versions prior to 1.6.8. The `fromJSON` and `fromCrossJSON` deserializers fail to validate array element lists and the termination boundaries (`done` and `throw` indices) of sequence nodes. By supplying out-of-bounds indices or forged array-like structures, an unauthenticated remote attacker can construct an iterator with an unreachable exit condition or trigger excessive loop iterations, halting the single-threaded JavaScript event loop and causing a denial of service.

Amit Schendel
Amit Schendel
7 views•10 min read
•about 5 hours ago•CVE-2026-116582
4.7

CVE-2026-116582: Cross-Site Scripting via Unescaped RegExp Serialization in Seroval

CVE-2026-116582 is an improper output escaping vulnerability in the Seroval JavaScript serialization library that leads to cross-site scripting (XSS). When Seroval serializes RegExp objects into executable JavaScript literals for embedding in HTML script elements, it fails to neutralize the less-than character ('<'). If an application constructs a regular expression from untrusted input and embeds the serialized output inside an inline script block during server-side rendering (SSR), an attacker can inject a closing script tag to break out of the JavaScript context and execute arbitrary client-side code.

Amit Schendel
Amit Schendel
4 views•11 min read