Unsafe deserialization (CWE-502, OWASP A08 Software and Data Integrity Failures) enables remote code execution when attacker-controlled serialized objects are reconstructed by a library that executes code during deserialization. The node-serialize library is the canonical Node.js example: it evaluates immediately-invoked function expressions (IIFEs) embedded in the serialized payload. NIST 800-53 SI-10 requires validation of all input before processing. Unlike JSON.parse (which only creates primitive values and plain objects), unsafe deserialization libraries can reconstruct class instances, triggering constructor side effects defined by the attacker.
Low because exploiting unsafe deserialization requires a specific vulnerable library to be used on attacker-controlled input, but successful exploitation achieves arbitrary code execution.
Replace unsafe deserialization libraries with JSON.parse followed by Zod schema validation. Never call node-serialize.unserialize() on untrusted input:
import { z } from 'zod'
// Unsafe — executes IIFEs in the payload:
// const data = require('node-serialize').unserialize(userInput)
// Safe — only parses JSON primitives, then validates shape:
const DataSchema = z.object({
type: z.enum(['config', 'preferences']),
value: z.number().int().nonnegative(),
})
const parsed = JSON.parse(userInput) // No code execution
const data = DataSchema.parse(parsed) // Throws on invalid shape
Audit package.json for node-serialize, serialize-javascript (when used to deserialize), or qs with allowPrototypes: true — these are the most commonly exploited deserialization vectors in Node.js.
ID: security-hardening.secrets-config.deserialization
Severity: low
What to look for: List all deserialization points where external data is parsed (JSON.parse with eval, pickle, yaml.load, unserialize). For each, search for deserialization of untrusted data: eval(), JSON.parse() of user data without schema validation, node-serialize, serialize-javascript usage for untrusted data. The most dangerous patterns involve deserialization libraries that execute code during the deserialization process.
Pass criteria: JSON.parse is used (not eval) for JSON data, followed by schema validation. No deserialization libraries that support arbitrary code execution (node-serialize, serialized-object) process untrusted input — 100% of deserialization must use safe methods (no eval, no unsafe load). Report: "X deserialization points found, all Y use safe parsing methods."
Fail criteria: User-provided serialized data is deserialized using a library that supports arbitrary code execution during deserialization (e.g., node-serialize.unserialize(userInput)).
Skip (N/A) when: The application does not deserialize any user-provided serialized objects (JSON with schema validation is fine).
Detail on fail: "node-serialize.unserialize() called on user-provided data in lib/session.ts — IIFE execution during deserialization possible" or "eval() used to parse user-submitted configuration data"
Remediation: Use JSON with schema validation only — never deserialize objects that can reconstruct class instances from untrusted input:
// Bad: executes code during deserialization
const data = require('node-serialize').unserialize(userInput)
// Good: JSON.parse + schema validation
import { z } from 'zod'
const DataSchema = z.object({ type: z.string(), value: z.number() })
const parsed = JSON.parse(userInput) // Only parses, no code execution
const data = DataSchema.parse(parsed) // Validates types and shape