Interlace ESLint
ESLint Interlace
Secure CodingRules

no-unvalidated-user-input

Detects unvalidated user input usage (req.body, req.query, etc.) in Express, Fastify, and Next.js applications. This rule is part of [`eslint-plugin-secure-codi

Keywords: input validation, CWE-20, security, ESLint rule, user input, req.body, req.query, validation library, Zod, Joi, Yup, class-validator, OWASP, input security, auto-fix, LLM-optimized, code security

Detects unvalidated user input usage (req.body, req.query, etc.) in Express, Fastify, and Next.js applications. This rule is part of eslint-plugin-secure-coding and provides LLM-optimized error messages that AI assistants can automatically fix.

⚠️ This rule warns by default in the recommended config.

Quick Summary

AspectDetails
CWE ReferenceCWE-20 (Improper Input Validation)
SeverityHigh (security vulnerability)
Auto-Fix✅ Yes (suggests validation libraries)
CategorySecurity
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForAll web applications handling user input, API endpoints, form submissions

Vulnerability and Risk

Vulnerability: Failing to validate user input allows attackers to send malformed or malicious data to the application. Risk: This is the root cause of many vulnerabilities, including SQL Injection, XSS, and Remote Code Execution. It can also lead to application crashes or logic errors if data doesn't match expected formats.

Error Message Format

The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:

🔒 CWE-20 OWASP:A06 CVSS:7.5 | Improper Input Validation detected | HIGH [SOC2,PCI-DSS,HIPAA,GDPR,ISO27001]
   Fix: Review and apply the recommended fix | https://owasp.org/Top10/A06_2021/

Message Components

ComponentPurposeExample
Risk StandardsSecurity benchmarksCWE-20 OWASP:A06 CVSS:7.5
Issue DescriptionSpecific vulnerabilityImproper Input Validation detected
Severity & ComplianceImpact assessmentHIGH [SOC2,PCI-DSS,HIPAA,GDPR,ISO27001]
Fix InstructionActionable remediationFollow the remediation steps below
Technical TruthOfficial referenceOWASP Top 10

Rule Details

Unvalidated user input is a critical security vulnerability that can lead to injection attacks, data corruption, and unauthorized access. This rule detects direct usage of user input sources without validation.

Why This Matters

IssueImpactSolution
🔒 SecurityInjection attacks (SQL, XSS, etc.)Use validation libraries
🐛 Data IntegrityInvalid data can corrupt systemsZod, Joi, Yup validation
🔐 Type SafetyRuntime errors from wrong typesType-safe validation
📊 ComplianceViolates security best practicesInput validation required

Detection Patterns

The rule detects:

  • Express patterns: req.body, req.query, req.params, req.headers, req.cookies
  • Fastify patterns: request.body, request.query, request.params
  • Next.js patterns: searchParams
  • Generic patterns: Variables named userInput, input

Examples

❌ Incorrect

// Unvalidated Express request body
app.post('/api/users', (req, res) => {
  const { email, name } = req.body; // ❌ No validation
  // Use email and name directly
});

// Unvalidated query parameters
app.get('/api/search', (req, res) => {
  const query = req.query.q; // ❌ No validation
  // Use query directly
});

// Unvalidated route parameters
app.get('/api/users/:id', (req, res) => {
  const userId = req.params.id; // ❌ No validation
  // Use userId directly
});

✅ Correct

// Validated with Zod
import { z } from 'zod';

const userSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1),
});

app.post('/api/users', (req, res) => {
  const data = userSchema.parse(req.body); // ✅ Validated
  // Use data safely
});

// Validated with Joi
import Joi from 'joi';

const querySchema = Joi.object({
  q: Joi.string().required(),
});

app.get('/api/search', (req, res) => {
  const { value } = querySchema.validate(req.query); // ✅ Validated
  // Use value safely
});

// Validated with class-validator
import { IsString, IsUUID } from 'class-validator';

class UserParams {
  @IsUUID()
  id!: string;
}

app.get('/api/users/:id', (req, res) => {
  const params = plainToClass(UserParams, req.params);
  validate(params); // ✅ Validated
  // Use params safely
});

Configuration

{
  rules: {
    'secure-coding/no-unvalidated-user-input': ['error', {
      allowInTests: false,                    // Allow in test files
      trustedLibraries: ['zod', 'joi', 'yup', 'class-validator'], // Trusted validation libraries
      ignorePatterns: []                     // Additional safe patterns to ignore
    }]
  }
}

Options

OptionTypeDefaultDescription
allowInTestsbooleanfalseAllow unvalidated input in test files
trustedLibrariesstring[]['zod', 'joi', 'yup', 'class-validator']Trusted validation libraries to recognize
ignorePatternsstring[][]Additional safe patterns to ignore

Rule Logic Flow

Best Practices

1. Use Zod for Type-Safe Validation

import { z } from 'zod';

const userSchema = z.object({
  email: z.string().email(),
  age: z.number().int().min(18),
});

app.post('/api/users', (req, res) => {
  try {
    const data = userSchema.parse(req.body);
    // Use validated data
  } catch (error) {
    res.status(400).json({ error: 'Invalid input' });
  }
});

2. Use Joi for Flexible Validation

import Joi from 'joi';

const schema = Joi.object({
  email: Joi.string().email().required(),
  name: Joi.string().min(1).required(),
});

app.post('/api/users', (req, res) => {
  const { error, value } = schema.validate(req.body);
  if (error) {
    return res.status(400).json({ error: error.details[0].message });
  }
  // Use validated value
});

3. Use class-validator for DTOs

import { IsString, IsEmail, MinLength } from 'class-validator';
import { plainToClass } from 'class-transformer';
import { validate } from 'class-validator';

class CreateUserDto {
  @IsEmail()
  email!: string;

  @IsString()
  @MinLength(1)
  name!: string;
}

app.post('/api/users', async (req, res) => {
  const dto = plainToClass(CreateUserDto, req.body);
  const errors = await validate(dto);
  if (errors.length > 0) {
    return res.status(400).json({ errors });
  }
  // Use validated dto
});

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Values from Variables

Why: Values stored in variables are not traced.

// ❌ NOT DETECTED - Value from variable
const value = userInput;
dangerousOperation(value);

Mitigation: Validate all user inputs.

Wrapper Functions

Why: Custom wrappers not recognized.

// ❌ NOT DETECTED - Wrapper
myWrapper(userInput); // Uses dangerous API internally

Mitigation: Apply rule to wrapper implementations.

Dynamic Invocation

Why: Dynamic calls not analyzed.

// ❌ NOT DETECTED - Dynamic
obj[method](userInput);

Mitigation: Avoid dynamic method invocation.

Resources

On this page