← Toutes les actualités
data-exposure4 min de lecture

Your Error Messages Are Leaking Secrets to Attackers

Par Seaworthy · 2 octobre 2026

Lines of code displayed on a screen

Photo by Florian Olivo on Unsplash

I reviewed a codebase last week that an AI assistant wrote almost entirely. Every endpoint returned a neat JSON object with a stack array showing table names, exact file paths, and library versions. The developer called it helpful for debugging. He had no idea he was publishing a map of his backend to anyone who sent a malformed request.

This is not a rare mistake. AI coding assistants love verbose errors. They were trained on tutorials where clarity matters more than security. When you ask an assistant to "return useful error messages," you get a gift basket of internal state. And because the code runs without throwing exceptions, it feels finished.

Why this pattern lands in production

Three forces push verbose errors out the door.

First, debugging friction. During development you want the full trace. You want to know which SQL query failed and which column was missing. The assistant writes that behavior, you test it, everything works. Nothing in the happy path forces you to revisit the error handler.

Second, the assistant has no ops context. It does not know your logging pipeline, your feature flags, or your staging setup. It gives you the simplest thing that works. That simplicity is almost always "send the exception message to the client."

Third, copy-paste culture. A single catch block gets replicated across twenty routes. The leak scales with your API surface.

What leaks, exactly

A stack trace can contain database table and column names, internal file paths, framework and library versions, cloud resource identifiers, and sometimes environment variable names. A caught database error can include the full SQL statement with parameter names. A validation error can echo back the entire request body, including tokens or passwords that arrived in the wrong field.

Attackers do not need a sophisticated exploit. They send garbage. They watch the response. That is a reconnaissance step, and you handed it over for free.

Worse, verbose errors often skip logging. The developer sees the error in the client during testing, so they assume it is visible everywhere. In production nobody reads those responses. You get silent failures and an exposed schema at the same time.

The fix is boring and effective

Route all unexpected exceptions through a single handler. Return a generic message and a correlation ID. Log the full detail server side with that same ID. Clients can report the ID to support. Nobody else learns your table names.

Here is the pattern in a Node/Express style, without any runnable exploit:

// bad: leaks internals
app.use((err, req, res, next) => {
  res.status(500).json({ error: err.message, stack: err.stack });
});

// better: generic response, full detail only in logs
const crypto = require('crypto');
app.use((err, req, res, next) => {
  const correlationId = crypto.randomUUID();
  logger.error({ correlationId, err, path: req.path });
  res.status(500).json({
    error: 'Internal server error',
    correlationId
  });
});

For client errors (400-level), be specific about what the caller did wrong but do not echo internal identifiers. "Missing field: email" is fine. "Column users.email_address violates not-null constraint" is not.

Why AI assistants make this harder

Assistants are optimized for the next token, not for your threat model. When you prompt "add error handling," you get error handling. You do not get data classification, log routing, or response shaping. Those are ops decisions. If you skip them, the assistant will fill the gap with the most obvious behavior, which is disclosure.

I am not blaming the tools. I am blaming the workflow. Developers use AI to move fast, then skip the security review because the code looks clean. A clean-looking catch block is not a secure one.

What to do today

Search your codebase for err.stack, error.message inside response bodies, and any place a caught exception is serialized directly. Grep for res.send(err), res.json(error), and similar patterns. If you find them, replace with a generic response and a server-side log line.

Add a test that asserts a malformed request returns a 500 without the words "stack" or "at " in the body. That test will fail the first time you run it. Fix the code, keep the test.

When you prompt an AI assistant next, include the constraint. Say "return a generic error to the client and log the details." You will get better code, and you will stop publishing your schema to strangers.

Seaworthy provides security assessment services for teams that want this kind of issue caught before deployment.

Cet article a été généré par IA et résume des sources publiquement disponibles.

Par les créateurs de Seaworthy

Seaworthy analyse votre dépôt pour détecter les problèmes abordés dans des articles comme celui-ci.

Failles de sécurité, secrets exposés et mauvaises configurations détectés avant le déploiement. Gratuit, aucun compte requis.

$ npx seaworthycode