LOW: Login rate limiter bypassed when no users exist (first-run timing window)
LOW: CORS_ORIGIN accepts comma-separated origins without URL validation
LOW: LIVE constant interpolated into SQL queries in payments.js
MEDIUM: CSRF cookie defaults to httpOnly=false - XSS bypasses CSRF protection
MEDIUM: Admin routes use req.params.id without integer validation
MEDIUM: No pagination on core list endpoints - returns all records
MEDIUM: TrackerPage.jsx is 2386 lines with 44 hooks - maintainability and re-render risks
MEDIUM: 10x .catch(() => {}) silently swallowing errors in client code
MEDIUM: Floating-point REAL type for monetary amounts in SQLite
HIGH: No explicit JSON body size limit on express.json() - default 100KB
HIGH: No process-level unhandledRejection/uncaughtException handler
HIGH: Payment UPDATE/DELETE lack user_id in WHERE clause (defense-in-depth)
HIGH: SQL injection surface in analyticsService.js - string interpolation in WHERE clause
CRITICAL: Incomplete user deletion - orphaned data risk
CRITICAL: SMTP password stored in plaintext in SQLite
CRITICAL: Async route handlers lack try/catch - unhandled rejections crash process