SECURITYCRITICALCVE-2026-59940

Critical Deserialization Flaw in Seroval JS Library (CVE-2026-59940)

Seroval < 1.5.3 allows attacker-controlled JSON Promise nodes to bypass reference validation in fromJSON(), enabling object forgery. CVSS 9.8.

Dylan H.

Security Team

August 19, 2026
5 min read
Critical Deserialization Flaw in Seroval JS Library (CVE-2026-59940)

Critical severity

Rated critical. Prioritise patching — see the remediation guidance below.

Affected Products

  • seroval < 1.5.3

Executive Summary

A critical deserialization vulnerability (CVE-2026-59940) has been disclosed in seroval, a popular JavaScript library for stringifying complex JS values — including Promises, Sets, Maps, and circular references — beyond what JSON.stringify supports. Versions prior to 1.5.3 are vulnerable.

CVSS Score: 9.8 (Critical)

The flaw exists in seroval.fromJSON(). Attacker-controlled JSON containing Promise control nodes can operate on values from the general deserialization reference table without verifying genuine intent, allowing an attacker to forge object references, trigger unintended code paths, or achieve object injection in the deserializing application.


Vulnerability Overview

AttributeValue
CVE IDCVE-2026-59940
CVSS Score9.8 (Critical)
TypeDeserialization / Object Forgery
Attack VectorNetwork (attacker-controlled JSON input)
Privileges RequiredNone
User InteractionNone
Affected Functionseroval.fromJSON()

Affected Versions

PackageAffected VersionsFixed Version
seroval< 1.5.31.5.3+

Technical Analysis

Background on Seroval

Seroval is designed to serialize JavaScript values that JSON cannot handle: Promises, undefined, BigInt, circular references, typed arrays, Maps, Sets, and more. It generates a structured JSON representation — including special "control nodes" — that fromJSON() can reconstruct back into live JS values.

The Vulnerability

The fromJSON() function processes a stream of serialized nodes, some of which are Promise control nodes that resolve or reject deferred values. These nodes reference other entries in the deserialization reference table — a lookup structure tracking all deserialized objects.

Prior to 1.5.3, fromJSON() did not validate that a Promise control node's target reference was actually a Promise before operating on it. An attacker who controls the JSON input can craft a payload where a Promise control node targets an arbitrary reference table entry — a plain object, function, or sensitive value — and triggers behaviors on it that were never intended.

Attack Scenario

// Vulnerable application accepting user-controlled serialized data
import { fromJSON } from 'seroval'; // version < 1.5.3
 
const userInput = JSON.parse(req.body.data); // attacker-controlled
const result = fromJSON(userInput);           // triggers the vulnerability
// Malicious payload: Promise control node targeting a non-Promise reference
{
  "t": { "0": <legitimate_object>, "1": <sensitive_target> },
  "r": 0,
  "v": [
    { "f": 1, "s": 1, "v": "<injected_value>" }
  ]
}

Potential Impact

ImpactDescription
Object ForgeryForce arbitrary reference table entries into unintended states
Prototype PollutionDepending on application code paths triggered post-deserialization
Application Logic BypassManipulate internal state to bypass authorization or business logic
Denial of ServiceCause unhandled rejections or state corruption that crashes the process
RCE (context-dependent)In environments where deserialized objects trigger code execution

Immediate Remediation

Step 1: Upgrade Seroval

# npm
npm update seroval
 
# yarn
yarn upgrade seroval
 
# pnpm
pnpm update seroval
 
# Verify installed version
node -e "const s = require('seroval'); console.log(require('./node_modules/seroval/package.json').version)"

Step 2: Audit Usage of fromJSON()

Search your codebase for any use of fromJSON with user-controlled input:

# Find all uses of fromJSON in the codebase
grep -rn "fromJSON" src/ --include="*.ts" --include="*.js" --include="*.mjs"
 
# Identify where input originates
grep -rn "fromJSON" src/ -A3 --include="*.ts"

Step 3: Validate Input Before Deserialization

If you cannot upgrade immediately, validate that fromJSON() input comes from trusted sources only:

import { fromJSON } from 'seroval';
 
function safeFromJSON(data: unknown, trustedSources: Set<string>) {
  if (!isTrustedSource(trustedSources)) {
    throw new Error('Untrusted deserialization source rejected');
  }
  return fromJSON(data as SerovalJSON);
}

Step 4: Monitor for Anomalous Promise Rejections

Until patched, enable unhandled rejection monitoring:

process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled rejection — possible CVE-2026-59940 exploitation attempt:', reason);
  // Alert your security monitoring system
});

Ecosystem Impact

Seroval is used as a dependency in several popular frameworks and libraries that handle server-side serialization and hydration. Projects using solid-js, react-query integrations, or custom SSR hydration pipelines that pass user-influenced data through seroval's serialization format are potentially affected.

# Check if seroval appears in your dependency tree
npm ls seroval
# or
pnpm why seroval

Detection Indicators

IndicatorDescription
Unhandled Promise rejections in logsDeserialization state corruption from exploit attempts
Malformed JSON with nested numeric keysCharacteristic of crafted seroval payloads
Unexpected object mutations in application stateSuccessful object forgery
Process crashes in Node.js servicesDoS from corrupted deserialization state

Post-Remediation Steps

  1. Upgrade seroval to 1.5.3+ across all services
  2. Audit all transitive dependencies using npm ls seroval
  3. Never pass user-controlled data directly to fromJSON() — deserialize from trusted serializers only
  4. Add input schema validation before any deserialization step
  5. Enable unhandled rejection logging as an ongoing monitoring measure
  6. Review your SSR hydration pipeline for attacker-influenced data paths

References