Opus
Health endpoint leaks which secrets are missing to unauthenticated callers
- apps/web/app/api/health/route.ts:17-26
- apps/web/app/api/health/route.ts:53-57
The GET handler has no authentication and returns the `missing` array verbatim in the JSON response. A public, anonymous attacker hitting /api/health can enumerate exactly which production secrets are unset (e.g. ANTHROPIC_API_KEY, GITHUB_APP_WEBHOOK_SECRET, CRON_SECRET). This is a directly useful reconnaissance signal: knowing CRON_SECRET is unset means the cron endpoint can be invoked; knowing GITHUB_APP_WEBHOOK_SECRET is unset means webhook signature verification is likely disabled. Additionally the DB error string is echoed (err.message), which on connection failures typically contains the DB host, user, and sometimes credentials parsed from DATABASE_URL by pg/drizzle, leaking infra topology. Standard practice is to return a boolean ok/not-ok publicly and gate the detailed payload behind a shared secret (e.g. the existing CRON_SECRET) or an internal-only path.
Recommendation
Either (a) require an auth header (Bearer of CRON_SECRET or a dedicated HEALTH_TOKEN) before returning the detailed payload and otherwise return only `{ok}` with status, or (b) drop the `missing` array and `error` string from the public response and log them server-side instead.