Summary
checkLockout / recordFailedAttempt in userAuth.controller.js gate failed attempts per user account. An attacker using a botnet or simple IP rotation can run unlimited password-spray attacks against any email address without ever triggering the lockout.
Impact
- Credential stuffing and password spray attacks succeed unimpeded.
- Accounts with weak or reused passwords are compromised silently.
Suggested Fix
Implement a two-dimensional rate limit:
- Per-account lockout after N failures (already present) - keep this.
- Per-IP rate limiting via
express-rate-limit on the /login route (missing).
- Optional: CAPTCHA challenge after 3 failures.
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 20,
keyGenerator: (req) => req.ip,
});
router.post('/login', loginLimiter, loginController);
Summary
checkLockout/recordFailedAttemptinuserAuth.controller.jsgate failed attempts per user account. An attacker using a botnet or simple IP rotation can run unlimited password-spray attacks against any email address without ever triggering the lockout.Impact
Suggested Fix
Implement a two-dimensional rate limit:
express-rate-limiton the/loginroute (missing).