Safeguard
Application Security•

CWE-7 J2EE Missing Custom Error Page: Stop Leaking Stack Traces

Default error pages and stack traces hand attackers your database type and container version. How CWE-7 happens in Java web apps and how to configure error pages.

Safeguard Security Team
3 min read

When a Java web application fails and the browser shows a stack trace, that page is a gift to anyone probing the site. CWE-7 names the problem: the application does not define its own default error page, so the container's built-in error response goes out instead.

MITRE's guidance is that a web application must define a default error page for 4xx errors such as 404 and 5xx errors such as 500, and must catch java.lang.Throwable exceptions. The goal is to keep attackers from mining information out of the container's error output.

How it happens

Servlet containers ship with generic error pages. They are helpful during development because they show the exception, the line and the call chain. In production the same pages describe your internals to strangers.

Three gaps tend to appear together:

  • No error page is mapped for common HTTP status codes.
  • No handler catches uncaught exceptions, so they bubble to the container.
  • Debug style output stays on after the release.

An attacker exploring a site looks for exactly this. MITRE points out that the amount of information a site gives away is often what decides whether an attack succeeds.

What an attacker gains

MITRE lists a confidentiality impact: read application data. Its example is specific. A stack trace might show a malformed SQL query string, the type of database in use, and the version of the application container. With that, the attacker can aim at known weaknesses in those exact components instead of guessing.

The error page does not break anything by itself. It makes every other attack cheaper.

How to find it

Trigger errors on purpose in a test environment. Request a path that does not exist. Send malformed parameters. Submit a form with a value the code cannot parse. Then read what comes back. Anything that names a class, a file path, a query or a version is a finding.

Also read the deployment descriptor and check whether error pages and exception types are mapped at all.

How to fix it

Map a generic page for status codes and for the Throwable type in the descriptor:

<error-page>
  <error-code>404</error-code>
  <location>/errors/not-found.html</location>
</error-page>
<error-page>
  <error-code>500</error-code>
  <location>/errors/server-error.html</location>
</error-page>
<error-page>
  <exception-type>java.lang.Throwable</exception-type>
  <location>/errors/server-error.html</location>
</error-page>

Then follow through:

  1. Make the pages plain. A short message and a reference ID is enough.
  2. Log the full exception on the server, where only your team can read it.
  3. Keep debug output out of production builds and configuration.
  4. Re-test after each release, since a new framework layer can bring its own default page.

Quick check

Why log the detail instead of hiding the error entirely?

Your team still needs the stack trace to fix the bug. Logging it server side keeps the detail for you and away from the visitor.

Is a 404 page really sensitive?

It can be. A default 404 often names the container and its version, which tells an attacker which known issues to try.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.