A generic, helpful message - never the raw exception.
Returning str(e) to clients leaks internal details: file paths, table names, database versions, library versions. None of that helps the caller, and all of it helps an attacker map your infrastructure and craft a targeted attack. The pattern is simple: log the full error on your server for debugging, and return only what the user can act on.
# WRONG - leaks internals
raise HTTPException(400, detail=f"Error: {str(e)}")
# RIGHT - log internally, return generic
logger.error(f"Query error: {e}")
raise HTTPException(400, detail="Query failed. Check SQL syntax.")
The one people forget: health endpoints. A health check that helpfully returns version numbers, file paths or configuration details is doing the same job as a leaky error message, just on a URL that is deliberately easy to find. Return status: ok and nothing else.
Note this is not about being unhelpful. "Query failed, check your SQL syntax" tells the caller what to do. "Table analytics_prod.users does not exist at /srv/app/db/handler.py line 214, psycopg2 2.9.3" tells an attacker where to aim.
Full item: https://www.tigzig.com/security/backend. Related: not publishing your internal API surface.
← All Agents FAQ