Brute Force Attack in Nestjs with Bearer Tokens
Brute Force Attack in Nestjs with Bearer Tokens — how this specific combination creates or exposes the vulnerability
A brute force attack against a NestJS API that uses Bearer tokens attempts to discover valid tokens by systematically trying many candidate values. Even when tokens are long and random, attackers can exploit weak entry points to test guesses at authentication boundaries. Because Bearer tokens are typically sent in the Authorization header, attackers focus on the login or token-introspection endpoints and any route that accepts an unvalidated token before enforcing authorization checks.
In NestJS, a common misconfiguration is allowing unauthenticated access to the route that validates or exchanges credentials. For example, if an endpoint like /auth/login does not enforce rate limits or does not use Captcha after repeated failures, an attacker can automate token guessing without being blocked. Additionally, if token validation logic is spread across multiple guards and interceptors without a centralized policy, some requests may bypass strict checks depending on route ordering or guard misconfiguration.
Another vector involves endpoints that return different responses for invalid tokens versus missing tokens. Distinguishing these responses enables attackers to iteratively refine guesses. If the application exposes stack traces or verbose errors in development mode, attackers gain hints about token validation internals. Even in production, timing differences—such as slightly faster 401 versus 403 responses—can leak information that aids offline brute force attempts.
Attackers may also target introspection or revocation endpoints. If these endpoints do not require strong authentication or are rate-limited, an attacker can probe whether guessed tokens are still active. Without proper monitoring, brute force attacks can persist for long periods, especially when attackers rotate IPs or use low-and-slow request patterns to evade simple threshold-based defenses.
Because middleBrick scans the unauthenticated attack surface, it can detect missing rate limiting on authentication and token validation routes, inconsistent error handling that leaks token validity, and missing controls around token introspection. These findings map to authentication weaknesses in the OWASP API Top 10 and can be surfaced alongside relevant guidance in the scan report.
Bearer Tokens-Specific Remediation in Nestjs — concrete code fixes
Remediation focuses on hardening authentication boundaries, standardizing token validation, and enforcing strict rate controls. The following examples assume JWT Bearer tokens and use NestJS core features such as Guards, Interceptors, and Pipes.
1. Centralized Auth Guard with strict token validation
Use a single guard to validate Bearer tokens on every request that requires protection. Avoid duplicating validation logic across controllers or services.
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private readonly jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractToken(request);
if (!token) {
request.user = null;
return false;
}
try {
const payload = await this.jwtService.verifyAsync(token);
request.user = payload;
return true;
} catch {
request.user = null;
return false;
}
}
private extractToken(request: Request): string | null {
const authHeader = request.headers['authorization'];
if (typeof authHeader !== 'string') return null;
const [type, token] = authHeader.split(' ');
return type.toLowerCase() === 'bearer' ? token : null;
}
}
2. Rate limiting on authentication endpoints
Apply a separate rate limit to login and token-introspection routes to slow down brute force attempts.
import { RateLimiterMemory } from 'rate-limiter-flexible';
const loginRateLimiter = new RateLimiterMemory({
points: 5, // 5 attempts
duration: 60, // per 60 seconds
});
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Post('login')
async login(@Body() dto: LoginDto, @Req() req: Request) {
try {
await loginRateLimiter.consume(req.ip);
} catch {
throw new HttpException('Too many attempts', HttpStatus.TOO_MANY_REQUESTS);
}
return this.authService.login(dto);
}
}
3. Consistent error responses and input validation
Ensure that invalid token and missing token responses are identical in timing and structure. Use validation pipes to reject malformed requests early.
import { UsePipes, ValidationPipe } from '@nestjs/common';
@UsePipes(new ValidationPipe({ whitelist: true }))
@Post('login')
async login(@Body() dto: LoginDto) {
// Always perform constant-time checks where possible
// and return the same generic error message
return this.authService.login(dto);
}
4. Token binding and rotation
Issue short-lived access tokens with refresh token rotation. Store token metadata server-side (e.g., in Redis) and check revocation status on each validation to mitigate replay and brute force impacts.
// Example token payload with jti and scope
{
"sub": "user-123",
"jti": "a1b2c3d4",
"scope": "read write",
"exp": 1735689600
}
5. MiddleBrick integration
Use the CLI to verify that your remediation reduces the attack surface: middlebrick scan <url>. The dashboard can track authentication scores over time, and the GitHub Action can enforce a minimum score before merges. The MCP Server allows you to run scans directly from your IDE while iterating on fixes.