← All fixes

Fix it

Leaking stack traces and error details to the client, how to fix it

Medium severityCWE-209 (Generation of Error Message Containing Sensitive Information)
We scanned nearly 2,000 AI-built apps and 1 in 8 shipped a high-severity flaw. Is this one in yours?Scan free →

When a handler catches an error and sends the raw message or stack trace back in the response, it exposes internal detail that helps an attacker: absolute file paths, framework and library versions, database column names, even fragments of failing queries. The fix is to log the full error where only you can see it and return a generic message with a reference id to the client.

Why it's a problem

Detailed errors turn blind probing into targeted attack. A leaked stack trace reveals the exact stack and versions to match against known exploits, a database error reveals table and column names for injection, and a path reveals your deployment layout. None of it is exploitable on its own, but together it removes the guesswork an attacker would otherwise need.

The pattern

app.get("/api/report", async (req, res) => {
  try {
    const data = await buildReport(req.query);
    res.json(data);
  } catch (err) {
    // leaks message + stack to the caller
    res.status(500).json({ error: err.message, stack: err.stack });
  }
});

The fix

app.get("/api/report", async (req, res) => {
  try {
    const data = await buildReport(req.query);
    res.json(data);
  } catch (err) {
    const ref = crypto.randomUUID();
    console.error(ref, err);            // full detail stays server-side
    res.status(500).json({ error: "Something went wrong", ref });
  }
});

Why AI tools write this

Echoing err.message back to the client is the shortest way to make an error visible during development, and it is genuinely useful while building. The assistant writes the debugging-friendly version and there is no prompt telling it to switch to a production-safe response, so the leak ships as written.

The quick fix

  • Log the full error and stack server-side; return a generic message to the client.
  • Attach a random reference id to both so you can correlate a report to a log entry.
  • Disable framework debug or verbose error pages in production.
  • Never include err.stack, query text, or file paths in a response body.

Common questions

How do I find where my app leaks stack traces?

Search for err.stack, err.message, and error.stack in response-building code. Check your global error handler specifically, since that is where unhandled errors are serialized into responses.

Is returning a generic error message enough if the HTTP status code reveals something?

HTTP status codes are generally fine to expose: 404, 401, 403, 500 are expected. The risk is the message body, which can include file paths, query structure, and library versions.

How do I correlate a production error to a log entry without exposing details to the user?

Generate a random reference id with crypto.randomUUID() at the catch boundary. Log the full error with that id server-side, and return only the id to the client for support correlation.

Want to know if this pattern is already in something you shipped? Scan your live app or a public repo free, no account needed.

Scan my app →

Related: Debug mode enabled in production

Catch this automatically: scan your GitHub repo · website vulnerability scanner · review every pull request · SAST for AI code · OWASP Top 10 for AI code

Leaking Stack Traces to the Client, Why It's a Risk and the Fix | Prbl