Problem Statement
The global ThrottlerGuard (api/src/app.module.ts:17-18) applies 100 requests per 60 seconds to every route including authentication endpoints (POST /auth/login, POST /auth/register). This default is far too generous for sensitive auth operations. Credential brute-force attacks can make 100 login attempts per minute per IP address without triggering any throttling response. There is no progressive backoff, no account lockout, and no CAPTCHA integration.
Evidence
// api/src/app.module.ts:17-18
ThrottlerModule.forRoot([{
ttl: parseInt(process.env.THROTTLE_TTL ?? "60000"),
limit: parseInt(process.env.THROTTLE_LIMIT ?? "100"),
}])
The auth controller has no route-specific throttling override:
// api/src/auth/auth.controller.ts — no @Throttle() or @SkipThrottle() decorator
@Post("login")
login(@Body() dto: LoginDto): Promise<AuthResponse> { ... }
Impact
Attackers can attempt 100 credential guesses per minute (6,000 per hour) per IP without triggering any defense. With distributed IPs, this scales to millions of attempts. Successful credential stuffing can lead to account takeover, data exfiltration, and stream hijacking.
Proposed Solution
- Apply
@Throttle({ default: { limit: 5, ttl: 900000 } }) (5 attempts per 15 minutes) on login and register endpoints
- Add IP-based progressive delay on repeated failures (store attempt count in cache)
- Return consistent error messages regardless of whether the email exists (already implemented in AuthService — good)
- Log auth failures to audit log for monitoring
- Add
Retry-After header on throttled responses (already supported by ThrottlerExceptionFilter)
Technical Requirements
- Must use NestJS
@Throttle() decorator without breaking global throttler config
- Must log auth failures with user-agent and IP for threat monitoring
- Must maintain backward compatibility with existing ThrottlerExceptionFilter
Acceptance Criteria
File Map
api/src/auth/auth.controller.ts — add @Throttle decorators
api/src/auth/auth.service.ts — add failure logging
api/src/app.module.ts — verify global throttler config
Dependencies
- Related: REPO-007 (token refresh needs rate limiting too)
- Related: REPO-001 (real auth needed for accurate failure tracking)
Testing Strategy
- Unit: Test ThrottlerGuard behavior with mocked request counts
- Integration: Test that 6 rapid login requests trigger 429 on the 6th
- Verify that different IPs get independent rate limits
- Test that non-auth endpoints are not affected
Security Considerations
The error message must remain consistently "invalid email or password" (already done) to prevent email enumeration. Rate limit responses should not distinguish between valid and invalid credentials. Consider adding a rate-limit bypass for trusted internal services.
Definition of Done
Labels: security, high impact
Priority: High
Difficulty: Intermediate
Estimated Effort: 1d
Milestone: v1.0-alpha
Labels: security,high impact
Priority: High | Difficulty: Intermediate | Estimated Effort: 1d
Backlog ID: REPO-005
Problem Statement
The global ThrottlerGuard (
api/src/app.module.ts:17-18) applies100 requests per 60 secondsto every route including authentication endpoints (POST /auth/login,POST /auth/register). This default is far too generous for sensitive auth operations. Credential brute-force attacks can make 100 login attempts per minute per IP address without triggering any throttling response. There is no progressive backoff, no account lockout, and no CAPTCHA integration.Evidence
The auth controller has no route-specific throttling override:
Impact
Attackers can attempt 100 credential guesses per minute (6,000 per hour) per IP without triggering any defense. With distributed IPs, this scales to millions of attempts. Successful credential stuffing can lead to account takeover, data exfiltration, and stream hijacking.
Proposed Solution
@Throttle({ default: { limit: 5, ttl: 900000 } })(5 attempts per 15 minutes) on login and register endpointsRetry-Afterheader on throttled responses (already supported by ThrottlerExceptionFilter)Technical Requirements
@Throttle()decorator without breaking global throttler configAcceptance Criteria
File Map
api/src/auth/auth.controller.ts— add @Throttle decoratorsapi/src/auth/auth.service.ts— add failure loggingapi/src/app.module.ts— verify global throttler configDependencies
Testing Strategy
Security Considerations
The error message must remain consistently "invalid email or password" (already done) to prevent email enumeration. Rate limit responses should not distinguish between valid and invalid credentials. Consider adding a rate-limit bypass for trusted internal services.
Definition of Done
Labels: security, high impact
Priority: High
Difficulty: Intermediate
Estimated Effort: 1d
Milestone: v1.0-alpha
Labels: security,high impact
Priority: High | Difficulty: Intermediate | Estimated Effort: 1d
Backlog ID: REPO-005