Auth Bypass in Nestjs (Typescript)
Typescript-Specific Remediation in Nestjs — concrete code fixes
To mitigate auth bypass vulnerabilities in NestJS with TypeScript, enforce authentication at the most granular level possible and leverage TypeScript’s type system to prevent unsafe assumptions. Always apply guards at the route level for sensitive endpoints, even if controller-level guards exist, and use custom decorators that combine metadata with runtime validation.
Replace ad-hoc metadata checks with a robust AuthGuard that explicitly validates the presence and integrity of the user object. For example, instead of relying on request.user being set by a previous guard, verify it within the guard using a service that checks token validity and user existence:
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise {
const request = context.switchToHttp().getRequest();
const authHeader = request.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
throw new UnauthorizedException('Missing or malformed token');
}
const token = authHeader.split(' ')[1];
try {
const payload = this.jwtService.verify(token, { secret: process.env.JWT_SECRET });
// Attach validated user to request — TypeScript knows this is safe after verification
request.user = { userId: payload.sub, email: payload.email, roles: payload.roles };
return true;
} catch (error) {
throw new UnauthorizedException('Invalid or expired token');
}
}
}
Use this guard explicitly on routes that require authentication, avoiding blanket controller-level application when some routes should be public:
@Controller('users')
export class UsersController {
constructor(private usersService: UsersService) {}
@Get()
@UseGuards(JwtAuthGuard) // All routes under this controller require auth by default
findAll() {
return this.usersService.findAll();
}
@Get('public')
// Explicitly allow public access — overrides controller guard
@UseGuards()
getPublicInfo() {
return { message: 'Publicly accessible' };
}
@Get('profile')
@UseGuards(JwtAuthGuard) // Re-apply guard for clarity and safety
getProfile(@Req() req) {
// TypeScript knows req.user is defined and has expected structure
return { userId: req.user.userId, email: req.user.email };
}
}
Additionally, use TypeScript interfaces to strictly type the request.user property across the application. Declare an augmentation in src/types/express.index.d.ts:
// src/types/express.index.d.ts
import { User } from '../users/user.entity';
declare namespace Express {
interface Request {
user: User | null;
}
}
This ensures that any attempt to access request.user without proper guard validation results in a compile-time error if the property is missing or incorrectly typed, closing a common bypass vector where guards are skipped but code assumes authentication.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |
Frequently Asked Questions
Can TypeScript interfaces prevent auth bypass in NestJS?
request.user only compiles when a guard has properly set and typed that property. Combined with explicit guard usage, this creates a compile-time safety net for authentication logic.Why is it dangerous to rely only on controller-level guards in NestJS?
@UseGuards() array or disable them via custom metadata like setMetadata('skip-auth', true). This creates a false sense of security—TypeScript will not warn you if a route unintentionally excludes the guard, leading to potential auth bypass.