Production error responses do not expose stack traces
Why it matters
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.
Severity rationale
Critical because exposed stack traces provide attackers with dependency versions, file paths, and SQL structure — directly enabling targeted exploitation of known CVEs.
Remediation
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.
Detection
-
ID:
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_ENVor environment-conditional error detail. In Next.js, checkapp/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.
External references
- cwe · CWE-209 — Generation of Error Message Containing Sensitive Information
- cwe · CWE-497 — Exposure of Sensitive System Information to an Unauthorized Control Sphere
- cwe · CWE-200 — Exposure of Sensitive Information to an Unauthorized Actor
- owasp:2021 · A04 — Insecure Design
- owasp:2021 · A09 — Security Logging and Monitoring Failures
Taxons
History
- 2026-04-17·v1.0.0·Initial import from security-headers·automated