Application-wide security hardening following a vulnerability assessment and penetration test: secrets moved to environment variables, fail-closed API authentication, tenant-bound tokens, login lockout, and tightened cookie/CSP policy.
Secrets Moved to Environment Variables
The Django SECRET_KEY, n8n password, and ZeptoMail API key are no longer committed to source. Production now hard-fails to start if DJANGO_SECRET_KEY is missing, preventing an accidental fallback to a known default.
Fail-Closed API Authentication
The default DRF permission changed from allow-all to IsAuthenticated, so any endpoint that forgets to declare its own permission class is now rejected by default rather than silently exposed. Public endpoints (login, password reset, token refresh) explicitly opt back in to anonymous access.
Login Rate Limiting & Account Lockout
Login attempts are now throttled (5/min), password reset requests (5/hour) and MFA verification (10/min) are rate-limited, and repeated failed logins trigger a temporary account lockout.
Tenant-Bound Login Tokens
Login tokens now carry the tenant they were issued for and are rejected if replayed against a different tenant, closing a cross-tenant token-replay path.
Customer & Bank Reconciliation Endpoints Secured
Fixed a set of Customer-related and Bank Reconciliation API endpoints that were reachable without authentication.