← 全部新闻
data-exposure4 分钟阅读

Your Error Messages Are Leaking Secrets: A Wake-Up Call for AI-Assisted Developers

作者:Seaworthy · 2026年10月16日

A rusted padlock hanging on a chain-link gate

Photo by Meritt Thomas on Unsplash

I get it. You're using an AI coding assistant to ship features fast. The assistant writes a try/catch, returns the exception message, and you move on. It works in development. But in production, that same pattern can hand attackers a map of your internal systems. Overly verbose error messages are a data exposure bug, and they're everywhere in AI-generated code.

The problem

When an unhandled exception occurs, many frameworks default to returning a detailed error response. That response might include a full stack trace, database query fragments, file paths, environment variable names, and even snippets of source code. Developers see this in local development and think it's helpful. It is. In production, it's a gift to anyone probing your API.

AI assistants often replicate this pattern because they're trained on code that does exactly that. They don't know your deployment context. They see res.status(500).json({ error: err.message, stack: err.stack }) and think it's fine. It's not.

Why it matters

Attackers use error messages for reconnaissance. A stack trace tells them which framework and version you're running. A database error reveals table and column names. A file path exposes your directory structure. Even a simple ENOENT: no such file or directory, open '/app/config/secrets.json' tells them where to look next.

This isn't theoretical. Bug bounty programs regularly pay for verbose errors. Automated scanners look for them. And because AI assistants can generate hundreds of endpoints in a day, the exposure scales with your velocity.

A common pattern

Here's a typical Express.js route that an AI might write. It looks harmless.

app.get('/user/:id', async (req, res) => {
  try {
    const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
    res.json(user.rows[0]);
  } catch (err) {
    res.status(500).json({
      error: err.message,
      stack: err.stack,
      query: err.query
    });
  }
});

If the database is down or the query fails, the client gets the full error message, the stack trace, and possibly the SQL query. That's a data exposure incident waiting to happen.

The fix

You need two things: a generic client-facing message and detailed server-side logging. Never send internal details to the client. Log them where only your team can see them.

app.get('/user/:id', async (req, res) => {
  try {
    const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
    res.json(user.rows[0]);
  } catch (err) {
    // Log full details server-side
    logger.error('Failed to fetch user', { userId: req.params.id, error: err });
    // Send generic message to client
    res.status(500).json({ error: 'Internal server error' });
  }
});

This is not about hiding errors from your users. It's about controlling what information leaves your system. A generic message is enough for the client. Your logs have the rest. If you need to correlate a client report with a server log, include a request ID in both.

Other places this shows up

Verbose errors aren't just in HTTP responses. They appear in:

  • GraphQL resolvers that return raw exception messages.
  • WebSocket error events that broadcast stack traces.
  • CLI tools that print environment variables on failure.
  • Mobile apps that display debug info in release builds.

AI assistants will happily generate all of these if you don't specify otherwise. You need to review every error path, not just the obvious ones.

What to do today

First, search your codebase for patterns like err.message, err.stack, error.stack, and exception.toString() in any code that sends data to a client. Second, check your framework's default error handler. Many frameworks have a production mode that suppresses details, but it's often off by default. Third, add a linter rule or a code review checklist item that flags verbose error responses. Fourth, test your production error responses. Send a bad request and see what comes back. You might be surprised.

My take

I think the AI coding assistant boom has made this worse. Assistants optimize for working code, not secure code. They don't know that your staging environment is public or that your error messages are indexed by search engines. Developers who skip security and ops basics are the most vulnerable because they trust the generated code. That trust is misplaced.

You can still move fast. Just add one rule: never return internal error details to a client. It's a small change that prevents a large class of data exposure bugs. And if you want a second set of eyes on your error handling, Seaworthy offers a free security check for common misconfigurations like this one.

本文由 AI 生成,总结了公开可用的来源。

来自 Seaworthy 团队

Seaworthy 会扫描你的代码仓库,发现类似本文提到的各种问题。

安全漏洞、泄露的密钥和配置错误——在部署前捕获。免费运行,无需账户。

$ npx seaworthycode