eslint-plugin-nestjs-security
v1.0.4
Published
Security-focused ESLint rules for NestJS applications. Detects missing guards, validation pipes, throttling, exposed sensitive fields, and more.
Maintainers
Readme
eslint-plugin-nestjs-security
🔐 Security-focused ESLint plugin for NestJS applications. Detects missing guards, validation pipes, throttling, and exposed private fields with AI-optimized fix guidance.
NestJS-first security: This plugin provides comprehensive security rules for NestJS applications. With 5 security rules mapped to OWASP Top 10, CWE and CVSS, it transforms your linter into a NestJS security auditor that AI assistants can understand and fix.
💡 What you get
- NestJS-focused coverage: 5 rules targeting NestJS-specific vulnerabilities (guards, validation, throttling, serialization).
- LLM-optimized & MCP-ready: Structured 2-line messages with CWE + OWASP + CVSS + concrete fixes so humans and AI auto-fixers stay aligned.
- Standards aligned: OWASP Top 10 Web 2021, CWE tagging, CVSS scoring in every finding for compliance mapping.
- Tiered presets:
recommended,strictfor fast policy rollout. - Decorator-aware: Detects @UseGuards, @UsePipes, @Throttle, @Exclude, class-validator decorators.
- Low false positive rate: Context-aware detection with production heuristics.
Every security rule produces a structured 2-line error message:
src/users/users.controller.ts
18:5 error 🔒 CWE-284 OWASP:A01 CVSS:9.8 | Missing Authorization Guards | CRITICAL [SOC2,PCI-DSS]
Fix: Add @UseGuards(AuthGuard): @UseGuards(AuthGuard) before the handler | https://docs.nestjs.com/...Each message includes:
- 🔒 CWE reference - vulnerability classification
- 📋 OWASP category - Top 10 mapping
- 📊 CVSS score - severity rating (0.0-10.0)
- 🏢 Compliance tags - affected frameworks (SOC2, PCI-DSS, HIPAA)
- ✅ Fix instruction - exact code to write
- 📚 Documentation link - learn more
📊 OWASP Top 10 Coverage Matrix
| OWASP Category | Coverage | Rules |
| ----------------------------- | :------: | ------------------------------------------------------- |
| A01:2021 Access Control | ✅ | require-guards, no-exposed-private-fields |
| A03:2021 Injection | ✅ | no-missing-validation-pipe, require-class-validator |
| A05:2021 Misconfiguration | ✅ | require-throttler |
[!TIP] For complete OWASP coverage, combine with
eslint-plugin-secure-codingwhich provides 78 additional rules covering all OWASP categories.
🔐 5 Security Rules
💼 = Set in recommended | ⚠️ = Warns in recommended | 🔧 = Auto-fixable | 💡 = Suggestions
Authorization & Access Control (2 rules)
| Rule | CWE | OWASP | CVSS | Description | 💼 | ⚠️ | 🔧 | 💡 | | ------------------------------------------------------- | ------- | ----- | ---- | --------------------------------------- | --- | --- | --- | --- | | require-guards | CWE-284 | A01 | 9.8 | Require @UseGuards on controllers | 💼 | | | 💡 | | no-exposed-private-fields | CWE-200 | A01 | 7.5 | Detect exposed sensitive fields in DTOs | 💼 | | | 💡 |
Input Validation (2 rules)
| Rule | CWE | OWASP | CVSS | Description | 💼 | ⚠️ | 🔧 | 💡 | | --------------------------------------------------------- | ------ | ----- | ---- | ---------------------------------- | --- | --- | --- | --- | | no-missing-validation-pipe | CWE-20 | A03 | 8.6 | Require ValidationPipe for DTOs | 💼 | | | 💡 | | require-class-validator | CWE-20 | A03 | 7.5 | Require class-validator decorators | | ⚠️ | | 💡 |
Rate Limiting & DoS (1 rule)
| Rule | CWE | OWASP | CVSS | Description | 💼 | ⚠️ | 🔧 | 💡 | | --------------------------------------- | ------- | ----- | ---- | --------------------------------- | --- | --- | --- | --- | | require-throttler | CWE-770 | A05 | 7.5 | Require ThrottlerGuard/rate limit | | ⚠️ | | 💡 |
🔍 Rule Details
require-guards
Requires @UseGuards decorator on controllers or route handlers for access control.
❌ Incorrect
@Controller('users')
class UsersController {
@Get()
findAll() {} // No authentication/authorization
}✅ Correct
import { UseGuards } from '@nestjs/common';
import { AuthGuard } from './auth.guard';
@Controller('users')
@UseGuards(AuthGuard) // Class-level protection
class UsersController {
@Get()
findAll() {}
}
// Or method-level
@Controller('users')
class UsersController {
@Get()
@UseGuards(AuthGuard) // Method-level protection
findAll() {}
}no-missing-validation-pipe
Requires ValidationPipe for DTO input parameters to prevent injection attacks.
❌ Incorrect
@Controller('users')
class UsersController {
@Post()
create(@Body() dto: CreateUserDto) {} // No validation
}✅ Correct
import { UsePipes, ValidationPipe } from '@nestjs/common';
@Controller('users')
@UsePipes(new ValidationPipe()) // Class-level
class UsersController {
@Post()
create(@Body() dto: CreateUserDto) {}
}
// Or in main.ts (global)
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);require-throttler
Requires ThrottlerGuard or @Throttle decorator to prevent DoS and brute-force attacks.
❌ Incorrect
@Controller('auth')
class AuthController {
@Post('login')
login() {} // No rate limiting - vulnerable to brute force
}✅ Correct
import { Throttle, ThrottlerGuard } from '@nestjs/throttler';
@Controller('auth')
@UseGuards(ThrottlerGuard)
class AuthController {
@Post('login')
@Throttle({ default: { limit: 5, ttl: 60000 } }) // 5 attempts per minute
login() {}
}
// Or in app.module.ts (global)
@Module({
imports: [ThrottlerModule.forRoot([{ ttl: 60000, limit: 10 }])],
})
export class AppModule {}no-exposed-private-fields
Detects sensitive fields in DTOs/entities that are not excluded from serialization.
❌ Incorrect
@Entity()
class User {
id: string;
email: string;
password: string; // Exposed in API responses!
}✅ Correct
import { Exclude } from 'class-transformer';
@Entity()
class User {
id: string;
email: string;
@Exclude()
password: string; // Hidden from API responses
}
// Make sure to use ClassSerializerInterceptor
@UseInterceptors(ClassSerializerInterceptor)
@Controller('users')
class UsersController { ... }require-class-validator
Requires class-validator decorators on DTO properties for input validation.
❌ Incorrect
class CreateUserDto {
name: string; // No validation
email: string; // No validation
}✅ Correct
import { IsString, IsEmail, IsNotEmpty, MinLength } from 'class-validator';
class CreateUserDto {
@IsString()
@IsNotEmpty()
@MinLength(2)
name: string;
@IsEmail()
@IsNotEmpty()
email: string;
}🚀 Quick Start
ESLint Flat Config (Recommended)
// eslint.config.js
import nestjsSecurity from 'eslint-plugin-nestjs-security';
export default [
nestjsSecurity.configs.recommended,
// ... other configs
];Strict Mode
import nestjsSecurity from 'eslint-plugin-nestjs-security';
export default [nestjsSecurity.configs.strict];📋 Available Presets
| Preset | Description |
| ----------------- | ---------------------------------------------------------------------- |
| recommended | Balanced security for NestJS projects (critical as error, others warn) |
| strict | Maximum security enforcement (all rules as errors) |
⚠️ Global Configuration Handling
Static Analysis Limitation: ESLint analyzes files independently. It cannot detect cross-file configurations like
app.useGlobalGuards()inmain.tswhile lintingusers.controller.ts.
Understanding the Problem
NestJS supports two security configuration approaches:
| Approach | Example | ESLint Can See? |
| -------------------- | ------------------------------------------------- | :-------------: |
| Per-Controller | @UseGuards(AuthGuard) on class | ✅ |
| Per-Method | @UseGuards(AuthGuard) on method | ✅ |
| Global (main.ts) | app.useGlobalGuards(new AuthGuard()) | ❌ |
| Global (Module) | ThrottlerModule.forRoot({ ttl: 60, limit: 10 }) | ❌ |
Solution: assumeGlobal* Options
For teams using global configuration, set assumeGlobal*: true to disable per-file checks:
// eslint.config.js
import nestjsSecurity from 'eslint-plugin-nestjs-security';
export default [
{
...nestjsSecurity.configs.recommended,
rules: {
// Tell ESLint: "We have app.useGlobalGuards() in main.ts"
'nestjs-security/require-guards': ['warn', { assumeGlobalGuards: true }],
// Tell ESLint: "We have app.useGlobalPipes(new ValidationPipe()) in main.ts"
'nestjs-security/no-missing-validation-pipe': [
'warn',
{ assumeGlobalPipes: true },
],
// Tell ESLint: "We have ThrottlerModule.forRoot() in app.module.ts"
'nestjs-security/require-throttler': [
'warn',
{ assumeGlobalThrottler: true },
],
},
},
];Alternative: Use Skip Decorators
The rules recognize common "bypass" decorators for intentionally unprotected endpoints:
// These bypass require-guards
@Public() // nestjs-passport pattern
@SkipAuth() // common custom decorator
@AllowAnonymous() // alternative naming
@NoAuth() // alternative naming
// These bypass require-throttler
@SkipThrottle() // @nestjs/throttler built-inConfiguration Matrix
| Rule | assumeGlobal* Option | Skip Decorators |
| ---------------------------- | ----------------------- | ----------------------------------- |
| require-guards | assumeGlobalGuards | @Public, @SkipAuth, @AllowAnonymous |
| no-missing-validation-pipe | assumeGlobalPipes | (none - use assumeGlobal) |
| require-throttler | assumeGlobalThrottler | @SkipThrottle |
| require-class-validator | N/A (always local) | N/A |
| no-exposed-private-fields | N/A (always local) | @Exclude (is the solution) |
🔮 Future: Cross-File Global Detection (Planned)
We're planning dedicated rules to verify global configuration exists:
require-global-guards→ Ensuresmain.tscontainsapp.useGlobalGuards()require-global-validation-pipe→ Ensuresmain.tscontainsapp.useGlobalPipes()require-global-throttler→ Ensuresapp.module.tsimportsThrottlerModule
This will enable a "trust but verify" approach for teams using global configuration.
🏢 Enterprise Integration Example
// eslint.config.js
import nestjsSecurity from 'eslint-plugin-nestjs-security';
export default [
// Baseline for all NestJS apps
nestjsSecurity.configs.recommended,
// Strict mode for payment/auth services
{
files: ['src/auth/**', 'src/payments/**'],
...nestjsSecurity.configs.strict,
},
];🤖 LLM & AI Integration
This plugin is optimized for ESLint's Model Context Protocol (MCP), enabling AI assistants like Cursor, GitHub Copilot, and Claude to:
- Understand the exact vulnerability type via CWE references
- Apply the correct fix using structured guidance
- Provide educational context to developers
// .cursor/mcp.json
{
"mcpServers": {
"eslint": {
"command": "npx",
"args": ["@eslint/mcp@latest"]
}
}
}🔗 Related ESLint Plugins
Part of the Interlace ESLint Ecosystem — AI-native security plugins with LLM-optimized error messages:
| Plugin | Downloads | Description | Rules |
| ---------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------: | -------------------------------------------------------------------------- | :---: |
| eslint-plugin-secure-coding | | Framework-agnostic security (OWASP Web + Mobile Top 10) | 89 |
|
eslint-plugin-express-security | | Express.js security (CORS, cookies, CSRF, helmet) | 8 |
|
eslint-plugin-lambda-security | | AWS Lambda/Middy security (API Gateway, CORS, secrets) | 5 |
|
eslint-plugin-jwt | | JWT security (algorithm confusion, weak secrets, claims validation) | 13 |
|
eslint-plugin-crypto | | Cryptographic best practices (weak algorithms, key handling, CVE-specific) | 24 |
|
eslint-plugin-pg | | PostgreSQL/node-postgres security and best practices | 13 |
|
eslint-plugin-vercel-ai-security | | Vercel AI SDK security (OWASP LLM + Agentic Top 10) | 19 |
🔒 Privacy
This plugin runs 100% locally. No data ever leaves your machine.
📄 License
MIT © Ofri Peretz
