Debug and admin endpoints that AI-generated code leaves in production
Por Seaworthy · 25 de junio de 2026
Photo by Luke Chesser on Unsplash
Debug and admin endpoints that AI-generated code leaves in production
AI assistants are genuinely useful for scaffolding. Ask Copilot or Claude to bootstrap an Express app, a Next.js API, or a FastAPI service and you'll get a working skeleton in seconds. The problem is that "working skeleton" often includes routes you only needed during development: a /debug endpoint that dumps environment variables, a /metrics page without auth, an /admin panel protected by nothing but a comment that says // TODO: add authentication.
These don't get removed. They ship.
Why this keeps happening
The model doesn't know whether you're building something you'll deploy in five minutes or something that will sit in a staging environment forever. It's optimizing for immediate usefulness. So it adds a /health route that returns your database connection string, an /api/debug/config endpoint that returns the full parsed config object, and a /__internal/reset route it uses to wipe state during testing. Handy. Also a disaster.
The other factor is how code gets reviewed. When a human reads a diff, they're looking at what changed, not what already existed. A debug endpoint that was added three sprints ago by an AI assistant won't appear in the diff for your current PR. It's already there. Nobody's looking at it.
What these endpoints actually expose
Let me be specific about the blast radius. The most common category is environment variable leakage. Something like this:
// Added by AI assistant during initial scaffolding
app.get('/debug/env', (req, res) => {
res.json(process.env);
});
That single route exposes your database credentials, your JWT signing secret, your third-party API keys, and whatever else lives in your environment. No authentication required. No logging. Just a clean JSON response for anyone who finds it.
Admin panels are the second category. A scaffolded admin UI often ships with a route like /admin that's protected by a middleware the developer intended to write but never did. The frontend renders fine. The backend checks nothing. You now have an unauthenticated admin panel in production.
Internal metrics endpoints are the third. Prometheus-format /metrics routes are designed to be scraped by internal infrastructure, not exposed to the public internet. They often contain request rates, error rates, slow query counts, and enough information for an attacker to map your application's weak points.
How to audit your route list
If you're using Express, you can print every registered route at startup:
function printRoutes(app) {
app._router.stack
.filter(r => r.route)
.forEach(r => {
const methods = Object.keys(r.route.methods).join(', ').toUpperCase();
console.log(`${methods} ${r.route.path}`);
});
}
For Next.js, your route list is your filesystem. Run this from the project root:
find ./app ./pages/api -type f -name "*.ts" -o -name "*.tsx" | sort
Read every path with fresh eyes. Ask yourself: if someone hit this URL without a session cookie, what would they see? If the answer is "something they shouldn't", you have a problem.
For FastAPI, the /docs and /redoc endpoints are enabled by default. They document every route in your application, authenticated or not. In production, disable them:
app = FastAPI(docs_url=None, redoc_url=None)
Gate these endpoints properly
"Properly" means more than checking for a boolean isAdmin flag. For internal diagnostic routes, the right pattern is to bind them to an internal-only network interface, or require a secret header that only your infrastructure can set, or disable them entirely via an environment variable.
// Only register debug routes when explicitly enabled
if (process.env.DEBUG_ROUTES_ENABLED === 'true') {
app.get('/debug/env', requireInternalToken, (req, res) => {
// Even then, never return process.env directly
res.json({ nodeEnv: process.env.NODE_ENV });
});
}
The default should be off. Opt-in to enabling debug routes, not opt-out from disabling them.
For admin panels, middleware that checks for authentication is not enough if it can be bypassed. Make sure the middleware is applied at the router level, not just on individual child routes. A common mistake is protecting /admin/users but forgetting that /admin itself renders the full panel.
What to do right now
Pull up your application's full route list. Filter for any path containing: debug, admin, internal, metrics, health, status, info, config, test, or dev. For each match, check two things: does it require authentication, and does it return data that could help an attacker.
If you're not sure whether a route is safe to expose, the answer is to protect it anyway. The cost of adding an auth check is minutes. The cost of an exposed /debug/env endpoint is everything.
AI assistants will keep scaffolding these routes because they're useful scaffolding. The responsibility for removing or gating them before deployment sits with you.
Seaworthy's configuration checks include detection of unauthenticated admin and debug routes in common frameworks, and will flag them in its static analysis report.
Este artículo fue generado por IA y resume fuentes públicamente disponibles.
Seaworthy analiza tu repositorio en busca de los problemas que se tratan en artículos como este.
Brechas de seguridad, secretos expuestos y configuraciones erróneas detectados antes de desplegar. Gratis, sin cuenta necesaria.