Nestjs security
Skill hlsitechio/claude-skills-security/appsec-stack-pack/nestjs-security
Security audit for NestJS applications including Guards (AuthGuard, RolesGuard), Interceptors, Pipes (ValidationPipe), custom decorators, module structure, dependency injection scoping, GraphQL/REST integration, microservices (TCP, Redis, Kafka transports), and NestJS-specific patterns. Use this skill whenever the user mentions NestJS, @nestjs/common, @nestjs/core, Guards, Interceptors, ValidationPipe, NestFactory, @Injectable, @Module, @Controller, @UseGuards, @UseInterceptors, or asks "audit my NestJS app", "NestJS guards safe", "ValidationPipe security". Trigger when the codebase contains `@nestjs/core` or `@nestjs/common` in package.json.From its SKILL.md
npx -y skills add hlsitechio/claude-skills-security --skill nestjs-securityAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 8 commands, including `grep -E '"@nestjs/(core|common|platform-express|platform-fastify)":' package.json` and 7 more.
SKILL.md
8.1 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
NestJS Security Audit
Audit NestJS applications. NestJS sits on top of Express or Fastify; specific patterns (decorators, DI, modules) introduce their own audit surface.
When this skill applies
- Reviewing Guards and authorization logic
- Auditing ValidationPipe configuration
- Reviewing Interceptors for unsafe transformations
- Checking module structure and provider scoping
- Reviewing GraphQL or REST controllers built on Nest
Workflow
Follow ../_shared/audit-workflow.md. Companion: nodejs-express-security for underlying middleware concerns.
Phase 1: Stack detection
grep -E '"@nestjs/(core|common|platform-express|platform-fastify)":' package.json
find . -name 'main.ts' -path '*src*' -not -path '*/node_modules/*'
find . -name 'nest-cli.json'
Detect: platform (Express vs Fastify), use of GraphQL (@nestjs/graphql), use of microservices (@nestjs/microservices).
Phase 2: Inventory
# Controllers and routes
grep -rn '@Controller\|@Get\|@Post\|@Put\|@Delete' src/ | head -50
# Guards
grep -rn '@UseGuards\|implements CanActivate' src/
# Interceptors
grep -rn '@UseInterceptors\|implements NestInterceptor' src/
# Pipes
grep -rn 'useGlobalPipes\|@UsePipes\|ValidationPipe' src/
# CORS
grep -rn 'enableCors\|cors:' src/main.ts src/app.module.ts 2>/dev/null
# Microservices
grep -rn 'createMicroservice\|@MessagePattern\|@EventPattern' src/
Phase 3: Detection — the checks
Guards
Guards implement CanActivate. They run before route handlers.
- NST-GUARD-1 Every endpoint that should be authenticated has
@UseGuards(AuthGuard)or global app-level guard. - NST-GUARD-2 Public endpoints explicitly marked (e.g.,
@Public()decorator), and the global guard checks for that decorator. Don't rely on "remembering" to apply guards.// GOOD pattern — global guard + opt-out app.useGlobalGuards(new AuthGuard(reflector)); // controllers/auth.controller.ts @Public() @Post('login') login(@Body() dto: LoginDto) { ... } - NST-GUARD-3 Role-based guards check the user's role against required roles via decorator metadata:
Verify@Roles('admin') @UseGuards(RolesGuard)RolesGuardactually readsRolesmetadata and compares. - NST-GUARD-4 Guards don't short-circuit silently — return
falseor throw; never resolve totrueon unexpected input. - NST-GUARD-5 Per-resource authz (ownership checks) NOT done in guards (guards don't have easy access to mutated body); done in service layer.
ValidationPipe
- NST-PIPE-1
app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true }))applied globally.whitelist: true— strips properties not declared on the DTO. Prevents mass assignment.forbidNonWhitelisted: true— REJECTS requests with extra properties (stricter).transform: true— converts payload to DTO class instance, applying transforms.
- NST-PIPE-2 DTOs use
class-validatordecorators (@IsString,@IsEmail,@Length, etc.). - NST-PIPE-3 Sensitive fields not exposed via
@Expose()fromclass-transformeron response DTOs (use@Exclude()for password hashes etc., or use serializer interceptor). - NST-PIPE-4 Nested DTOs use
@Type(() => Nested)for transform to work recursively.
// dto/create-user.dto.ts
import { IsEmail, IsString, Length, IsOptional } from 'class-validator';
export class CreateUserDto {
@IsEmail()
email!: string;
@IsString()
@Length(8, 128)
password!: string;
@IsString()
@Length(1, 50)
displayName!: string;
// role is intentionally not on the DTO — set by server
}
Interceptors
- NST-INT-1 Logging interceptors don't log full request body (password, secrets).
- NST-INT-2 Serialization interceptor strips sensitive response fields:
Combined with@UseInterceptors(ClassSerializerInterceptor)@Exclude()on the entity, ensures secrets don't ship. - NST-INT-3 Caching interceptors keyed by user/tenant when caching per-user data (otherwise cross-user cache hits).
Exception filters
- NST-EX-1 Global exception filter in production hides stack traces and internal error details.
- NST-EX-2 Specific HTTP exceptions (
UnauthorizedException,ForbiddenException,NotFoundException) used appropriately — don't return 500 for client errors. - NST-EX-3 Database error details (constraint names, table names) not bubbled to clients.
Middleware
NestJS supports both Express middleware and Nest-style middleware. Order matters:
- NST-MW-1 Security middleware (
helmet,cors) configured inmain.tsbeforeapp.listen(). - NST-MW-2 Rate limiting via
@nestjs/throttlerorexpress-rate-limit. Throttler applied globally or per-controller. - NST-MW-3
app.enableCors(...)with specific options (notenableCors()with default*).
Modules and DI scoping
- NST-DI-1 Request-scoped providers used for per-request state (e.g., logger with request ID). Don't put per-request data in singleton-scoped providers.
- NST-DI-2 Sensitive services (e.g., AuthService) only exported from modules that should access them; don't
exports: [AuthService]from auth module to public modules without need. - NST-DI-3
@Global()modules limited to truly global concerns.
Authentication strategies (Passport)
If using @nestjs/passport:
- NST-AUTH-1 JWT strategy validates signature, expiry, issuer, audience. See
saas-security-pack/saas-code-security-review/references/jwt-validation.md. - NST-AUTH-2 Local strategy compares password with
bcrypt.compare(constant-time); don't use===. - NST-AUTH-3 Session-based: connect session middleware before Passport.
- NST-AUTH-4 Refresh token rotation implemented (issue new RT on use, revoke old).
GraphQL (if using @nestjs/graphql)
- NST-GQL-1 Apollo Driver config:
introspectiondisabled in production,playgrounddisabled. - NST-GQL-2 Resolvers use
@UseGuards(...)for auth. - NST-GQL-3 See
graphql-securityskill for depth/complexity, field-level auth.
Microservices (TCP, Redis, Kafka, gRPC transports)
- NST-MS-1 Microservice transport not exposed publicly. TCP transport with default settings binds to all interfaces.
- NST-MS-2 Message handlers (
@MessagePattern) validate inputs — they're effectively RPC endpoints without HTTP middleware. - NST-MS-3 Inter-service auth: signed messages or mTLS between services; don't rely on network-only isolation.
File uploads
- NST-UP-1
@nestjs/platform-expressMulter config has size and count limits. - NST-UP-2 Validate file type by magic bytes (see
nodejs-express-security).
Config module
- NST-CFG-1
ConfigModulewithvalidatefunction ensures required env vars present at startup. - NST-CFG-2 Secrets accessed via
ConfigService.get('SECRET')— not fromprocess.envdirectly (so test/runtime config swapping works). - NST-CFG-3
validationSchema(Joi or Zod) requires specific env shape; fails fast on misconfiguration.
Dependencies
- NST-DEP-1 NestJS versions current (10.x or 11.x).
- NST-DEP-2 Companion:
nodejs-express-securityfor underlying Express/Fastify checks.
Phase 4: Triage
Critical: missing global ValidationPipe with whitelist; sensitive route without @UseGuards; CORS open with credentials; microservice handlers with no input validation.
Phase 5: Report
Use ../_shared/findings-schema.md. Prefix IDs with NST-.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.