Stack traces returned to API clients expose the internal file system paths, dependency names and versions, function call chains, and sometimes SQL queries that make up your application's internals. Attackers use this reconnaissance to identify vulnerable libraries, understand data model structure, and craft targeted exploits. CWE-209 (Generation of Error Message Containing Sensitive Information) and CWE-200 (Exposure of Sensitive Information) directly describe this class of leak. OWASP A04 (Insecure Design) and A09 (Security Logging and Monitoring Failures) both apply. AI-generated codebases are particularly prone to this: the default catch-and-return-error pattern is the path of least resistance when the model is filling in error handling.
Critical because exposed stack traces provide attackers with dependency versions, file paths, and SQL structure — directly enabling targeted exploitation of known CVEs.
Wrap every API route in a catch block that logs the full error internally but returns a generic message to the client. Never return err.message, err.stack, or the error object directly.
// src/app/api/example/route.ts
try {
// ... your logic
} catch (error) {
console.error('[API error]', error) // internal log — full detail
return Response.json(
{ error: 'Internal Server Error' },
{ status: 500 }
)
}
For Next.js pages, create app/error.tsx and app/global-error.tsx that render user-friendly messages without exposing the caught error. Use an error tracking service (Sentry, Datadog) to capture full traces server-side — then you get observability without client exposure.
ID: security-headers.info-exposure.no-stack-traces
Severity: critical
What to look for: Count all error handling locations: API route catch blocks, page error boundaries, and global error middleware. For each, check whether the full error object or stack trace is returned to the client. Check for NODE_ENV or environment-conditional error detail. In Next.js, check app/error.tsx, app/global-error.tsx, API route error handlers, and any global error middleware.
Pass criteria: No more than 0 error handlers expose stack traces or internal details to clients. Error responses return generic messages (e.g., "Internal Server Error", "Something went wrong") without stack traces, file paths, dependency names, SQL queries, or internal details. Error handling is either unconditionally safe (always returns generic messages) or environment-conditional (shows details only when NODE_ENV === 'development' or equivalent).
Fail criteria: Any API route or error handler returns full error objects, stack traces, or internal file paths to the client without environment checks.
Skip (N/A) when: Never — every project should handle errors safely.
Detail on fail: "API route /api/users catches errors but returns err.message and err.stack directly in JSON response" or "No error boundary configured — framework default may expose stack traces in production"
Remediation: Stack traces expose internal file paths, dependency versions, and logic that attackers can use. Return generic errors to clients:
// API route error handling
try {
// ... logic
} catch (error) {
console.error(error) // Log internally
return Response.json(
{ error: 'Internal Server Error' },
{ status: 500 }
)
}
For page errors, create a custom error boundary (app/error.tsx) that shows a user-friendly message.