feat(skills): add NestJS security testing module (#348)
This commit is contained in:
225
strix/skills/frameworks/nestjs.md
Normal file
225
strix/skills/frameworks/nestjs.md
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
---
|
||||||
|
name: nestjs
|
||||||
|
description: Security testing playbook for NestJS applications covering guards, pipes, decorators, module boundaries, and multi-transport auth
|
||||||
|
---
|
||||||
|
|
||||||
|
# NestJS
|
||||||
|
|
||||||
|
Security testing for NestJS applications. Focus on guard gaps across decorator stacks, validation pipe bypasses, module boundary leaks, and inconsistent auth enforcement across HTTP, WebSocket, and microservice transports.
|
||||||
|
|
||||||
|
## Attack Surface
|
||||||
|
|
||||||
|
**Decorator Pipeline**
|
||||||
|
- Guards: `@UseGuards`, `CanActivate`, execution context (HTTP/WS/RPC), `Reflector` metadata
|
||||||
|
- Pipes: `ValidationPipe` (whitelist, transform, forbidNonWhitelisted), `ParseIntPipe`, custom pipes
|
||||||
|
- Interceptors: response mapping, caching, logging, timeout — can modify request/response flow
|
||||||
|
- Filters: exception filters that may leak information
|
||||||
|
- Metadata: `@SetMetadata`, `@Public()`, `@Roles()`, `@Permissions()`
|
||||||
|
|
||||||
|
**Module System**
|
||||||
|
- `@Module` boundaries, provider scoping (DEFAULT/REQUEST/TRANSIENT)
|
||||||
|
- Dynamic modules: `forRoot`/`forRootAsync`, global modules
|
||||||
|
- DI container: provider overrides, custom providers
|
||||||
|
|
||||||
|
**Controllers & Transports**
|
||||||
|
- REST: `@Controller`, versioning (URI/Header/MediaType)
|
||||||
|
- GraphQL: `@Resolver`, playground/sandbox exposure
|
||||||
|
- WebSocket: `@WebSocketGateway`, gateway guards, room authorization
|
||||||
|
- Microservices: TCP, Redis, NATS, MQTT, gRPC, Kafka — often lack HTTP-level auth
|
||||||
|
|
||||||
|
**Data Layer**
|
||||||
|
- TypeORM: repositories, QueryBuilder, raw queries, relations
|
||||||
|
- Prisma: `$queryRaw`, `$queryRawUnsafe`
|
||||||
|
- Mongoose: operator injection, `$where`, `$regex`
|
||||||
|
|
||||||
|
**Auth & Config**
|
||||||
|
- `@nestjs/passport` strategies, `@nestjs/jwt`, session-based auth
|
||||||
|
- `@nestjs/config`, ConfigService, `.env` files
|
||||||
|
- `@nestjs/throttler`, rate limiting with `@SkipThrottle`
|
||||||
|
|
||||||
|
**API Documentation**
|
||||||
|
- `@nestjs/swagger`: OpenAPI exposure, DTO schemas, auth schemes
|
||||||
|
|
||||||
|
## High-Value Targets
|
||||||
|
|
||||||
|
- Swagger/OpenAPI endpoints in production (`/api`, `/api-docs`, `/api-json`, `/swagger`)
|
||||||
|
- Auth endpoints: login, register, token refresh, password reset, OAuth callbacks
|
||||||
|
- Admin controllers decorated with `@Roles('admin')` — test with user-level tokens
|
||||||
|
- File upload endpoints using `FileInterceptor`/`FilesInterceptor`
|
||||||
|
- WebSocket gateways sharing business logic with HTTP controllers
|
||||||
|
- Microservice handlers (`@MessagePattern`, `@EventPattern`) — often unguarded
|
||||||
|
- CRUD generators (`@nestjsx/crud`) with auto-generated endpoints
|
||||||
|
- Background jobs and scheduled tasks (`@nestjs/schedule`)
|
||||||
|
- Health/metrics endpoints (`@nestjs/terminus`, `/health`, `/metrics`)
|
||||||
|
- GraphQL playground/sandbox in production (`/graphql`)
|
||||||
|
|
||||||
|
## Reconnaissance
|
||||||
|
|
||||||
|
**Swagger Discovery**
|
||||||
|
```
|
||||||
|
GET /api
|
||||||
|
GET /api-docs
|
||||||
|
GET /api-json
|
||||||
|
GET /swagger
|
||||||
|
GET /docs
|
||||||
|
GET /v1/api-docs
|
||||||
|
GET /api/v2/docs
|
||||||
|
```
|
||||||
|
|
||||||
|
Extract: paths, parameter schemas, DTOs, auth schemes, example values. Swagger may reveal internal endpoints, deprecated routes, and admin-only paths not visible in the UI.
|
||||||
|
|
||||||
|
**Guard Mapping**
|
||||||
|
|
||||||
|
For each controller and method, identify:
|
||||||
|
- Global guards (applied in `main.ts` or app module)
|
||||||
|
- Controller-level guards (`@UseGuards` on the class)
|
||||||
|
- Method-level guards (`@UseGuards` on individual handlers)
|
||||||
|
- `@Public()` or `@SkipThrottle()` decorators that bypass protection
|
||||||
|
|
||||||
|
## Key Vulnerabilities
|
||||||
|
|
||||||
|
### Guard Bypass
|
||||||
|
|
||||||
|
**Decorator Stack Gaps**
|
||||||
|
- Guards execute: global → controller → method. A method missing `@UseGuards` when siblings have it is the #1 finding.
|
||||||
|
- `@Public()` metadata causing global `AuthGuard` to skip enforcement — check if applied too broadly.
|
||||||
|
- New methods added to existing controllers without inheriting the expected guard.
|
||||||
|
|
||||||
|
**ExecutionContext Switching**
|
||||||
|
- Guards handling only HTTP context (`getRequest()`) may fail silently on WebSocket or RPC, returning `true` by default.
|
||||||
|
- Test same business logic through alternate transports to find context-specific bypasses.
|
||||||
|
|
||||||
|
**Reflector Mismatches**
|
||||||
|
- Guard reads `SetMetadata('roles', [...])` but decorator sets `'role'` (singular) — guard sees no metadata, defaults to allow.
|
||||||
|
- `applyDecorators()` compositions accidentally overriding stricter guards with permissive ones.
|
||||||
|
|
||||||
|
### Validation Pipe Exploits
|
||||||
|
|
||||||
|
**Whitelist Bypass**
|
||||||
|
- `whitelist: true` without `forbidNonWhitelisted: true`: extra properties silently stripped but may have been processed by earlier middleware/interceptors.
|
||||||
|
- Missing `@Type(() => ChildDto)` on nested objects: `@ValidateNested()` without `@Type` means nested payload is never validated.
|
||||||
|
- Array elements: `@IsArray()` doesn't validate elements without `@ValidateNested({ each: true })` and `@Type`.
|
||||||
|
|
||||||
|
**Type Coercion**
|
||||||
|
- `transform: true` enables implicit coercion: strings → numbers, `"true"` → `true`, `"null"` → `null`.
|
||||||
|
- Exploit truthiness assumptions in business logic downstream.
|
||||||
|
|
||||||
|
**Conditional Validation**
|
||||||
|
- `@ValidateIf()` and validation groups creating paths where fields skip validation entirely.
|
||||||
|
|
||||||
|
**Missing Parse Pipes**
|
||||||
|
- `@Param('id')` without `ParseIntPipe`/`ParseUUIDPipe` — string values reach ORM queries directly.
|
||||||
|
|
||||||
|
### Auth & Passport
|
||||||
|
|
||||||
|
**JWT Strategy**
|
||||||
|
- Check `ignoreExpiration` is false, `algorithms` is pinned (no `none` or HS/RS confusion)
|
||||||
|
- Weak `secretOrKey` values
|
||||||
|
- Cross-service token reuse when audience/issuer not enforced
|
||||||
|
|
||||||
|
**Passport Strategy Issues**
|
||||||
|
- `validate()` return value becomes `req.user` — if it returns full DB record, sensitive fields leak downstream
|
||||||
|
- Multiple strategies (JWT + session): one may bypass restrictions of the other
|
||||||
|
- Custom guards returning `true` for unauthenticated as "optional auth"
|
||||||
|
|
||||||
|
**Timing Attacks**
|
||||||
|
- Plain string comparison instead of bcrypt/argon2 in local strategy
|
||||||
|
|
||||||
|
### Serialization Leaks
|
||||||
|
|
||||||
|
**Missing ClassSerializerInterceptor**
|
||||||
|
- If not applied globally, `@Exclude()` fields (passwords, internal IDs) returned in responses.
|
||||||
|
- `@Expose()` with groups: admin-only fields exposed when groups not enforced per-request.
|
||||||
|
|
||||||
|
**Circular Relations**
|
||||||
|
- Eager-loaded TypeORM/Prisma relations exposing entire object graph without careful serialization.
|
||||||
|
|
||||||
|
### Interceptor Abuse
|
||||||
|
|
||||||
|
**Cache Poisoning**
|
||||||
|
- `CacheInterceptor` without user/tenant identity in cache key — responses from one user served to another.
|
||||||
|
- Test: authenticated request, then unauthenticated request returning cached data.
|
||||||
|
|
||||||
|
**Response Mapping**
|
||||||
|
- Transformation interceptors may leak internal entity fields if mapping is incomplete.
|
||||||
|
|
||||||
|
### Module Boundary Leaks
|
||||||
|
|
||||||
|
**Global Module Exposure**
|
||||||
|
- `@Global()` modules expose all providers to every module without explicit imports.
|
||||||
|
- Sensitive services (admin operations, internal APIs) accessible from untrusted modules.
|
||||||
|
|
||||||
|
**Config Leaks**
|
||||||
|
- `forRoot`/`forRootAsync` configuration secrets accessible via `ConfigService` injection in any module.
|
||||||
|
|
||||||
|
**Scope Issues**
|
||||||
|
- Request-scoped providers (`Scope.REQUEST`) incorrectly scoped as DEFAULT (singleton) — request context leaks across concurrent requests.
|
||||||
|
|
||||||
|
### WebSocket Gateway
|
||||||
|
|
||||||
|
- HTTP guards don't automatically apply to WebSocket gateways — `@UseGuards` must be explicit.
|
||||||
|
- Authentication deferred from `handleConnection` to message handlers allows unauthenticated message sending.
|
||||||
|
- Room/namespace authorization: users joining rooms they shouldn't access.
|
||||||
|
- `@SubscribeMessage()` handlers relying on connection-level auth instead of per-message validation.
|
||||||
|
|
||||||
|
### Microservice Transport
|
||||||
|
|
||||||
|
- `@MessagePattern`/`@EventPattern` handlers often lack guards (considered "internal").
|
||||||
|
- If transport (Redis, NATS, Kafka) is network-accessible, messages can be injected bypassing all HTTP security.
|
||||||
|
- `ValidationPipe` may only be configured for HTTP — microservice payloads skip validation.
|
||||||
|
|
||||||
|
### ORM Injection
|
||||||
|
|
||||||
|
**TypeORM**
|
||||||
|
- `QueryBuilder` and `.query()` with template literal interpolation → SQL injection.
|
||||||
|
- Relations: API allowing specification of which relations to load via query params.
|
||||||
|
|
||||||
|
**Mongoose**
|
||||||
|
- Query operator injection: `{ password: { $gt: "" } }` via unsanitized request body.
|
||||||
|
- `$where` and `$regex` operators from user input.
|
||||||
|
|
||||||
|
**Prisma**
|
||||||
|
- `$queryRaw`/`$executeRaw` with string interpolation (but not tagged template).
|
||||||
|
- `$queryRawUnsafe` usage.
|
||||||
|
|
||||||
|
### Rate Limiting
|
||||||
|
|
||||||
|
- `@SkipThrottle()` on sensitive endpoints (login, password reset, OTP).
|
||||||
|
- In-memory throttler storage: resets on restart, doesn't work across instances.
|
||||||
|
- Behind proxy without `trust proxy`: all requests share same IP, or header spoofable.
|
||||||
|
|
||||||
|
### CRUD Generators
|
||||||
|
|
||||||
|
- Auto-generated CRUD endpoints may not inherit manual guard configurations.
|
||||||
|
- Bulk operations (`createMany`, `updateMany`) bypassing per-entity authorization.
|
||||||
|
- Query parameter injection in CRUD libraries: `filter`, `sort`, `join`, `select` exposing unauthorized data.
|
||||||
|
|
||||||
|
## Bypass Techniques
|
||||||
|
|
||||||
|
- `@Public()` / skip-metadata applied via composed decorators at method level causing global guards to skip via `Reflector` metadata checks
|
||||||
|
- Route param pollution: `/users/123?id=456` — which `id` wins in guards vs handlers?
|
||||||
|
- Version routing: v1 of endpoint may still be registered without the guard added to v2
|
||||||
|
- `X-HTTP-Method-Override` or `_method` processed by Express before guards
|
||||||
|
- Content-type switching: `application/x-www-form-urlencoded` instead of JSON to bypass JSON-specific validation
|
||||||
|
- Exception filter differences: guard throwing results in generic error that leaks route existence info
|
||||||
|
|
||||||
|
## Testing Methodology
|
||||||
|
|
||||||
|
1. **Enumerate** — Fetch Swagger/OpenAPI, map all controllers, resolvers, and gateways
|
||||||
|
2. **Guard audit** — Map decorator stack per method: which guards, pipes, interceptors are applied at each level
|
||||||
|
3. **Matrix testing** — Test each endpoint across: unauth/user/admin × HTTP/WS/microservice
|
||||||
|
4. **Validation probing** — Send extra fields, wrong types, nested objects, arrays to find pipe gaps
|
||||||
|
5. **Transport parity** — Same operation via HTTP, WebSocket, and microservice transport
|
||||||
|
6. **Module boundaries** — Check if providers from one module are accessible without proper imports
|
||||||
|
7. **Serialization check** — Compare raw entity fields with API response fields
|
||||||
|
|
||||||
|
## Validation Requirements
|
||||||
|
|
||||||
|
- Guard bypass: request to guarded endpoint succeeding without auth, showing guard chain break point
|
||||||
|
- Validation bypass: payload with extra/malformed fields affecting business logic
|
||||||
|
- Cross-transport inconsistency: same action authorized via HTTP but exploitable via WebSocket/microservice
|
||||||
|
- Module boundary leak: accessing provider or data across unauthorized module boundaries
|
||||||
|
- Serialization leak: response containing excluded fields (passwords, internal metadata)
|
||||||
|
- IDOR: side-by-side requests from different users showing unauthorized data access
|
||||||
|
- ORM injection: raw query with user-controlled input returning unauthorized data, or error-based evidence of query structure
|
||||||
|
- Cache poisoning: response from unauthenticated or different-user request matching a prior authenticated user's cached response
|
||||||
Reference in New Issue
Block a user