All guides
Medium severityError Handling & Resilience

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

Never return raw exceptions to the client

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 });
  }
}
Configure a custom error page

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.

Intercept at the proxy layer

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 free