Rule
Avoid recursion without depth protection.
Recursion without proper depth limiting risks stack
overflow and creates DoS vulnerabilities from malicious
input. Recursion with enforced depth limits and proper
bounds checking is acceptable.
Language support: 45+Introduction
Recursive functions without depth limits can exhaust the call stack, causing crashes. Malicious input like deeply nested JSON objects or cyclic data structures can trigger unbounded recursion intentionally. A single crafted request can crash your service by exceeding stack limits, creating a denial-of-service vulnerability that's trivial to exploit.
Why it matters
Security implications (DoS attacks): Attackers can craft input that triggers deep recursion, crashing your application. Deeply nested JSON, XML, or linked data structures are common attack vectors. A single malicious request exhausts the stack, taking down the entire service for all users.
System stability: Stack overflow errors crash the process immediately without graceful degradation. In production, this means dropped requests, interrupted transactions, and service unavailability. Recovery requires restarting the entire application.
Resource exhaustion: Unbounded recursion consumes stack memory exponentially. Each recursive call adds a stack frame, and deep recursion chains can consume megabytes of memory. This affects other processes on the same server and can trigger out-of-memory conditions.
Code examples
❌ Non-compliant:
function processNestedData(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
const result = {};
for (const key in obj) {
result[key] = processNestedData(obj[key]);
}
return result;
}Why it's wrong: No depth limit allows attackers to send deeply nested objects that exceed stack limits. Input like {a: {a: {a: {...}}}} nested 10,000 levels deep crashes the application with stack overflow. The function blindly recurses without checking depth.
✅ Compliant:
function processNestedData(obj, depth = 0, maxDepth = 100) {
if (depth > maxDepth) {
throw new Error('Maximum nesting depth exceeded');
}
if (typeof obj !== 'object' || obj === null) {
return obj;
}
const result = {};
for (const key in obj) {
result[key] = processNestedData(obj[key], depth + 1, maxDepth);
}
return result;
}Why this matters: The maxDepth parameter limits recursion to 100 levels, preventing stack overflow. This limit is high enough for legitimate nested data structures (most real-world data rarely exceeds 10-20 levels) while being low enough to stop attacks before consuming significant stack memory. Malicious deeply nested input throws an error instead of crashing the application. The depth check occurs before processing, failing fast when limits are exceeded.
Conclusion
Add depth parameters to all recursive functions that process external data. Set reasonable maximum depths based on expected data structure complexity. Throw errors or return default values when depth limits are exceeded instead of crashing.
.avif)
