Verbose error pages and stack traces in production
When an unhandled exception or a missing-route probe triggers a framework's debug error view in production, it can hand an attacker a map of your server: file paths, line numbers, library versions, and sometimes environment variables. The fix is to return generic error responses to users while logging full details only to a server-side service your team controls.
What it is
Every web framework ships with a built-in debug error view — Django's yellow exception page, Laravel's Ignition screen, Next.js's development overlay, Express's default exception dump. These are invaluable during development, but they're deliberately disabled in production builds. The risk is framework error pages that remain active because debug mode wasn't turned off, or custom error handlers that return raw exception objects directly in the response body.
AppSafe detects verbose errors by requesting a path that shouldn't exist on your site. If the response body matches patterns common to framework error pages — Python tracebacks, Node.js exception dumps, .NET exception details, Rails.root paths, or similar — the finding is reported as medium severity under Error Handling & Resilience.
Why it matters
A stack trace exposes the language and framework version, the internal directory structure of your app, the exact file and line that failed, and the call chain that led there. Paired with a CVE database, that information shortens the time from discovery to a targeted exploit — especially for known vulnerabilities in specific framework or library versions.
Debug pages can also include request data, partial environment variables, or SQL fragments in the rendered output, inadvertently leaking user input or server-internal values that should never reach a browser.
How to fix it
In Next.js API routes and Route Handlers, catch exceptions explicitly, log the full error server-side, and return a generic status to the caller.
// app/api/example/route.ts
export async function GET() {
try {
// ... handler logic ...
} catch (err) {
console.error(err); // logs stack trace to your server/monitoring only
return new Response("Internal Server Error", { status: 500 });
}
}Next.js renders pages/500.tsx (or app/error.tsx in the App Router) for unhandled errors in production. Populate it with a friendly message — no technical details — and wire up an error monitoring service like Sentry to capture the real exception.
For any error that escapes the app layer, nginx can substitute a static page for all 5xx responses before they reach the browser.
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
internal;
}FAQ
Does Next.js show stack traces in production builds?
The development overlay is already suppressed in production. The real risk is custom Route Handlers or API routes that catch an exception and serialize it directly into the response — something the framework won't prevent on its own.
How does AppSafe probe for verbose errors?
It requests a URL that doesn't exist on your site and scans the response body for phrases like 'Traceback (most recent call last)', 'Stack trace:', 'Unhandled Runtime Error', 'Exception Details:', and similar markers from Python, Node.js, PHP, Java, Ruby, and .NET frameworks.
My 404 page doesn't show a stack trace but AppSafe still flagged it. Why?
The scanner matches a broad set of patterns, some of which appear in partial or redacted error responses. Check whether exception class names, internal file paths, or framework identifiers appear anywhere in your 404 or 500 response body — even in a comment or a hidden element.
Is your app affected?
AppSafe checks for this and dozens of other issues in one free scan.
Scan my app freeRelated guides
Source maps in production leak your source code
Shipped .map files hand over your original source.
Dangerous HTTP methods: how TRACE, PUT, and DELETE get advertised
An OPTIONS response that lists TRACE or DELETE tells attackers more than it should.
Public GraphQL introspection: why it's a problem and how to turn it off
A single query returns your entire schema. Turn it off in production.