Stack Overflow in Adonisjs with Api Keys
Stack Overflow in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability
A Stack Overflow vulnerability in an AdonisJS application that uses API keys typically arises when unbounded or recursive operations are triggered by authenticated requests. When API keys are used for authentication but request handling does not limit depth or resource consumption, an attacker can craft inputs that cause recursive function calls or deeply nested data structures. This can exhaust the call stack, leading to a stack overflow that crashes the process or introduces instability.
Consider an endpoint that processes nested comments or tree-like data. If the handler recursively processes child nodes without a depth guard and requires an API key for access, an authenticated request with a deeply nested payload can trigger a stack overflow. AdonisJS relies on Node.js runtime behavior; Node does not always provide graceful stack exhaustion handling, and the process may terminate or become unresponsive.
For example, an unguarded recursive traversal like the following can be dangerous when processing user-supplied hierarchies:
// routes/comments.ts
Route.get('/comments/:id', async ({ params }) => {
const comment = await Comment.query().where('id', params.id).preload('children').first()
const traverse = (node) => {
if (!node.children || node.children.length === 0) return
node.children.forEach(traverse)
}
traverse(comment)
return comment
})
If an attacker sends a comment chain with thousands of nested children and includes a valid API key, the recursion depth can exceed the stack limit. Because the API key validates the request, the server treats it as authorized, but the operation is unbounded. This exposes the application to denial-of-service via stack exhaustion. MiddleBrick scans detect such unbounded recursion patterns during its 12 security checks, including Input Validation and Property Authorization, and highlight them in the report with severity and remediation guidance.
Additionally, in AdonisJS, middleware that validates API keys before entering route handlers can inadvertently allow deep or uncontrolled operations to proceed once authenticated. If the route logic does not enforce size or depth limits on user-controlled data, the combination of authenticated access and unchecked recursion creates a clear attack surface. The scanner’s BOLA/IDOR and Input Validation checks are designed to surface these risks by correlating spec definitions with runtime behavior.
Api Keys-Specific Remediation in Adonisjs — concrete code fixes
To remediate Stack Overflow risks when using API keys in AdonisJS, you should enforce strict limits on recursion depth, validate payload size, and avoid unbounded traversal of user-controlled data. Below are concrete code examples that demonstrate safe patterns.
1. Use an iterative approach with an explicit stack and a depth limit instead of recursion:
// Safe traversal with depth limit
Route.get('/comments/:id', async ({ params }) => {
const comment = await Comment.query().where('id', params.id).preload('children').first()
const maxDepth = 10
const stack = [{ node: comment, depth: 0 }]
const visited = []
while (stack.length > 0) {
const { node, depth } = stack.pop()
if (depth > maxDepth) {
throw new Error('Maximum traversal depth exceeded')
}
visited.push(node.id)
if (node.children && node.children.length > 0) {
node.children.forEach(child => {
if (!visited.includes(child.id)) {
stack.push({ node: child, depth: depth + 1 })
}
})
}
}
return comment
})
2. Validate the structure and size of incoming data before processing. For JSON payloads, enforce a maximum depth and node count:
// Validate nested payloads
const validatePayload = (obj, depth = 0) => {
const MAX_DEPTH = 5
if (depth > MAX_DEPTH) {
throw new Error('Payload nesting exceeds allowed depth')
}
if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
for (const key of Object.keys(obj)) {
validatePayload(obj[key], depth + 1)
}
}
}
Route.post('/data', async ({ request }) => {
const payload = request.body()
validatePayload(payload)
// proceed with safe processing
return { ok: true }
})
3. Apply rate limiting and request size constraints at the route or global level to reduce abuse opportunities:
// config/routes.ts
import Route from '@ioc:Adonis/Core/Route'
import { middleware } from '@ioc:Adonis/Addons/RateLimiter'
Route.group(() => {
Route.post('/data', (ctx) => {
// safe processing
}).middleware(['validateSize', 'rateLimit'])
}).prefix('api').middleware({
validateSize: async ({ request }, next) => {
const MAX_BODY_BYTES = 1024 * 10 // 10 KB
if ((request.rawBody as Buffer)?.length > MAX_BODY_BYTES) {
throw new Error('Request body too large')
}
return next()
},
rateLimit: middleware.rateLimit({
consumes: 100, // requests per window
every: 60000, // per minute
}),
})
These patterns reduce the likelihood of stack overflows by removing unbounded recursion, validating input structure, and enforcing resource constraints. When combined with API key authentication, they ensure that authorized requests remain within safe operational bounds.
MiddleBrick’s scans include checks for BFLA/Privilege Escalation and Input Validation, which can surface unbounded operations and missing guards in API key–protected routes. The findings include severity ratings and remediation guidance tailored to AdonisJS patterns.