ValidationPipe: Parameter pollution and DTO bypasses

NestJS uses class-validator to check incoming payloads against Data Transfer Objects (DTOs). A common finding is misconfiguring the global ValidationPipe. If you do not enable the whitelist property, the pipe validates the fields defined in the DTO, but allows other fields in the payload to pass through to your controller:

// VULNERABLE global ValidationPipe configuration
app.useGlobalPipes(new ValidationPipe({
  transform: true // Binds types, but does not strip unlisted parameters
}));

The Exploit: If the controller passes this DTO directly to TypeORM's save method, an attacker can append columns like role: "admin" to bypass business rules. We audit your pipe configuration to ensure it strips unlisted fields:

// SECURE ValidationPipe configuration
app.useGlobalPipes(new ValidationPipe({
  transform: true,
  whitelist: true, // Strips any parameter not explicitly defined in the DTO
  forbidNonWhitelisted: true // Rejects requests containing unlisted parameters
}));

Bypassing NestJS Guards

NestJS uses Guards (annotated with @UseGuards()) to verify authentication. A common implementation mistake is placing guards at the class level but forgetting to apply them to custom REST method overrides, or utilizing custom interceptors that mutate the request context. We audit your guard classes to check for authorization loopholes:

// VULNERABLE custom guard extracting unverified user headers
@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    // Bypass: trusts the client-passed header instead of validating JWT
    const userId = request.headers['x-user-id'];
    return !!userId;
  }
}

The Fix: All identity context must be derived from cryptographically verified JSON Web Tokens (JWT) verified server-side, never trusted directly from raw client-submitted headers.

Circular dependencies and Denial of Service (DoS)

NestJS uses dependency injection to manage classes. Circular dependencies (e.g., Module A imports Module B, which imports Module A) can cause memory exhaustion during server startup or container restarts. During our source code reviews, we run dependency analysis tools to identify circular references that could be exploited to crash services.

Example finding

DTO over-posting leading to database value overwrite

During an audit of a NestJS fintech backend, we identified an update user endpoint. The ValidationPipe had whitelist disabled. By appending the key "isVerified": true to our user update payload, the field passed validation and was processed by the TypeORM query, upgrading our test account's KYC tier. Fix priority: critical. Remediated by enabling whitelist on the global ValidationPipe.

Building scalable backend systems in NestJS? Schedule a security audit.

Book a NestJS Pentest

Frequently asked questions

Why is class-validator parameter pollution dangerous in NestJS?

If NestJS is configured with `ValidationPipe` but has `whitelist` set to false, the incoming request DTO will accept unexpected client-submitted JSON properties. These un-validated fields pass directly to typeorm/mongoose DB queries.

How do you bypass NestJS guards during a penetration test?

We audit NestJS guards to check if they trust client headers directly (such as `x-user-id` or `x-role`) without cryptographic validation, or if request context variables are mutated across concurrent calls.

What is the security risk of using custom NestJS decorators?

Custom decorators (like `@CurrentUser()`) read values from the request object. If they fail to validate the session state or pull data from un-sanitized fields, they introduce authorization flaws.

Related reading

Blog: Securing Node Express backends · JWT token mistakes · Next.js Server Actions security

Services: API security testing · Secure architecture review