Post 04

Security Hardening: 9 Critical Fixes

Code review findings and how we remediated 4 critical + 5 high priority security issues

Nov 26-29, 2025 14 min read Security, JWT, TOTP, CSRF
Security Audit Summary
4
Critical
5
High
9
Fixed
0
Remaining

The Audit Process

After completing the Node.js backend, we ran a comprehensive security audit. AI-assisted code review found issues that would have taken hours to catch manually. Here's what we found and how we fixed each one.

Critical Issues (4)

Issue #1 CRITICAL

JWT Secret Using Weak Fallback

The JWT configuration had a hardcoded fallback secret that would be used if the environment variable was missing.

Before (Vulnerable)
const JWT_SECRET = process.env.JWT_SECRET
  || 'fallback-secret-for-dev';
After (Fixed)
const JWT_SECRET = process.env.JWT_SECRET;
if (!JWT_SECRET) {
  throw new Error('JWT_SECRET required');
}
Issue #2 CRITICAL

TOTP Secrets Stored in Plaintext

MFA TOTP secrets were stored in the database without encryption, defeating the purpose of the envelope encryption system. Fixed by encrypting TOTP secrets with the user's DEK.

Issue #3 CRITICAL

No Rate Limiting on Auth Endpoints

Login, signup, and MFA verification had no rate limiting, allowing brute force attacks. Fixed with express-rate-limit: 5 attempts per 15 minutes for auth, 3 attempts per 5 minutes for MFA.

Issue #4 CRITICAL

Master Encryption Key Too Short

Documentation suggested a 32-character MEK, but AES-256 requires a 256-bit (64 hex character) key. Updated documentation with proper key generation: openssl rand -hex 32

High Priority Issues (5)

  • No CSRF Protection - Added csurf middleware with double-submit cookie pattern
  • Account Enumeration - Generic error messages for login failures
  • Missing Security Headers - Added Helmet with CSP, HSTS, and referrer policy
  • JWT Tokens Never Expire - Access tokens: 15 min, Refresh tokens: 7 days
  • No Account Lockout - 5 failed attempts triggers 15-minute lockout
Key Insights
  1. Security is never "done": Even with careful design, issues slip through.
  2. AI code review helps: Claude caught issues in minutes that might take hours manually.
  3. Defense in depth: Multiple layers (rate limiting + lockout + CSRF) work together.
  4. Follow established patterns: Don't reinvent auth - use proven libraries.

Security Checklist

  • ✅ No hardcoded secrets or fallbacks
  • ✅ All sensitive data encrypted at rest
  • ✅ Rate limiting on auth endpoints
  • ✅ CSRF protection on state-changing routes
  • ✅ Generic error messages (no enumeration)
  • ✅ Security headers via Helmet
  • ✅ JWT tokens with expiration
  • ✅ Account lockout after failed attempts
  • ✅ Input validation on all endpoints