Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
40 prioritized NestJS best practices across architecture, DI, security, performance, testing, and microservices.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/security-validate-all-input.md
1---2title: Validate All Input with DTOs and Pipes3impact: HIGH4impactDescription: First line of defense against attacks5tags: security, validation, dto, pipes6---78## Validate All Input with DTOs and Pipes910Always validate incoming data using class-validator decorators on DTOs and the global ValidationPipe. Never trust user input. Validate all request bodies, query parameters, and route parameters before processing.1112**Incorrect (trust raw input without validation):**1314```typescript15// Trust raw input without validation16@Controller('users')17export class UsersController {18@Post()19create(@Body() body: any) {20// body could contain anything - SQL injection, XSS, etc.21return this.usersService.create(body);22}2324@Get()25findAll(@Query() query: any) {26// query.limit could be "'; DROP TABLE users; --"27return this.usersService.findAll(query.limit);28}29}3031// DTOs without validation decorators32export class CreateUserDto {33name: string; // No validation34email: string; // Could be "not-an-email"35age: number; // Could be "abc" or -99936}37```3839**Correct (validated DTOs with global ValidationPipe):**4041```typescript42// Enable ValidationPipe globally in main.ts43async function bootstrap() {44const app = await NestFactory.create(AppModule);4546app.useGlobalPipes(47new ValidationPipe({48whitelist: true, // Strip unknown properties49forbidNonWhitelisted: true, // Throw on unknown properties50transform: true, // Auto-transform to DTO types51transformOptions: {52enableImplicitConversion: true,53},54}),55);5657await app.listen(3000);58}5960// Create well-validated DTOs61import {62IsString,63IsEmail,64IsInt,65Min,66Max,67IsOptional,68MinLength,69MaxLength,70Matches,71IsNotEmpty,72} from 'class-validator';73import { Transform, Type } from 'class-transformer';7475export class CreateUserDto {76@IsString()77@IsNotEmpty()78@MinLength(2)79@MaxLength(100)80@Transform(({ value }) => value?.trim())81name: string;8283@IsEmail()84@Transform(({ value }) => value?.toLowerCase().trim())85email: string;8687@IsInt()88@Min(0)89@Max(150)90age: number;9192@IsString()93@MinLength(8)94@MaxLength(100)95@Matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, {96message: 'Password must contain uppercase, lowercase, and number',97})98password: string;99}100101// Query DTO with defaults and transformation102export class FindUsersQueryDto {103@IsOptional()104@IsString()105@MaxLength(100)106search?: string;107108@IsOptional()109@Type(() => Number)110@IsInt()111@Min(1)112@Max(100)113limit: number = 20;114115@IsOptional()116@Type(() => Number)117@IsInt()118@Min(0)119offset: number = 0;120}121122// Param validation123export class UserIdParamDto {124@IsUUID('4')125id: string;126}127128@Controller('users')129export class UsersController {130@Post()131create(@Body() dto: CreateUserDto): Promise<User> {132// dto is guaranteed to be valid133return this.usersService.create(dto);134}135136@Get()137findAll(@Query() query: FindUsersQueryDto): Promise<User[]> {138// query.limit is a number, query.search is sanitized139return this.usersService.findAll(query);140}141142@Get(':id')143findOne(@Param() params: UserIdParamDto): Promise<User> {144// params.id is a valid UUID145return this.usersService.findById(params.id);146}147}148```149150Reference: [NestJS Validation](https://docs.nestjs.com/techniques/validation)151