# Improper Input Validation (CWE-20) The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly. - Prevalence: High Frequently exploited - Impact: High 6 high-severity rules - Prevention: Documented 13 fix examples **OWASP:** Broken Access Control (A01:2021-Broken Access Control) - #1 ## Description Input validation is a frequently-used technique for checking potentially dangerous inputs in order to ensure that the inputs are safe for processing within the code, or when communicating with other components. When software does not validate input properly, an attacker is able to craft the input in a form that is not expected by the rest of the application. ## Prevention Prevention strategies for Improper Input Validation based on 13 Shoulder detection rules. ### Python Use Pydantic models with Field validators instead of raw Request objects Validate business-critical inputs with range constraints using Pydantic or manual checks ### Go Parse string inputs to typed values and validate against business rules before use Use Echo struct binding with validation tags instead of untyped maps Use Fiber BodyParser with typed structs and validation tags ### Node.js Validate business-critical inputs with range checks before processing Use server-side prices from the database and validate ranges for business-critical values Add class-validator decorators to all DTO properties and enable the global ValidationPipe ## Warning Signs - [HIGH] Business-critical value extracted from user input without validation. This could allow attackers to manipulate prices, d - [HIGH] business-critical values from user input used without validation - [HIGH] DTO class '...' used in controller but lacks class-validator decorators. Unvalidated input may lead to injection attacks - [HIGH] Prisma ... uses unvalidated user input. Validate and whitelist fields before passing to Prisma. - [HIGH] Context creation uses raw request data without validation. Verify and validate all request data before adding to context - [HIGH] Procedure '...' accepts user input but lacks .input() validation. Add Zod schema to validate runtime data. - [HIGH] Entity '...' accepts user input but lacks class-validator decorators. Add validation to prevent invalid data. - [MEDIUM] FastAPI endpoints that accept raw Request objects instead of Pydantic models ## Consequences - Execute Unauthorized Code - Modify Application Data - DoS - Read Application Data ## Mitigations - Assume all input is malicious. Use an accept known good input validation strategy - When performing input validation, consider all potentially relevant properties - Do not rely exclusively on looking for malicious or malformed inputs ## Detection - Total rules: 13 - Languages: python, go, javascript, typescript ## Rules by Language ### Javascript (7 rules) - **Business Logic Input Validation** [MEDIUM]: Detects business-critical values (discount, refund, quantity) used without validation. - Remediation: Validate business-critical inputs before use. ```javascript function validateDiscount(discount) { const value = parseFloat(discount); if (isNaN(value) || value < 0 || value > 100) { throw new Error('Discount must be 0-100'); } return value; } const validated = validateDiscount(req.body.discount); applyDiscount(validated); ``` Learn more: https://shoulder.dev/learn/javascript/cwe-20/business-logic-input-validation - **Unvalidated Business-Critical Values** [HIGH]: Detects business-critical values from user input used without validation. - Remediation: Use server-side prices and validate ranges before use. ```javascript const product = products.get(productId); const total = product.price * quantity; ``` Learn more: https://shoulder.dev/learn/javascript/cwe-20/unvalidated-business-values - **NestJS DTO Missing Validation Decorators** [HIGH]: DTOs without class-validator decorators allow unvalidated input to flow into the application, enabling injection and data corruption. - Remediation: Add class-validator decorators to DTO properties. ```typescript import { IsString, IsEmail, MinLength } from 'class-validator'; class CreateUserDTO { @IsString() @MinLength(3) username: string; @IsEmail() email: string; } ``` Learn more: https://shoulder.dev/learn/typescript/cwe-20/dto-missing-validation - **Prisma Missing Input Validation** [HIGH]: Passing req.body directly to Prisma where/data allows users to filter by unauthorized fields and bypass access controls. - Remediation: Validate and whitelist fields with Zod before Prisma queries. ```typescript import { z } from 'zod'; const getUsersInput = z.object({ role: z.enum(['user', 'moderator']).optional(), status: z.enum(['active', 'inactive']).optional() }); async function getUsers(req: Request) { const input = getUsersInput.parse(req.query); return await prisma.user.findMany({ where: input }); } ``` Learn more: https://shoulder.dev/learn/typescript/cwe-20/prisma-missing-input-validation - **tRPC Unsafe Context Usage** [HIGH]: Using unvalidated headers, cookies, or query params in context creation allows attackers to bypass authentication and impersonate users. - Remediation: Verify JWT signatures or use session libraries instead of trusting raw headers. ```typescript import { getServerSession } from 'next-auth'; export async function createContext({ req, res }: CreateNextContextOptions) { const session = await getServerSession(req, res, authOptions); return { user: session?.user ?? null, db }; } ``` Learn more: https://shoulder.dev/learn/typescript/cwe-20/context-injection - **tRPC Procedure Missing Input Validation** [HIGH]: tRPC procedures without .input() validation accept unvalidated payloads at runtime, enabling injection and type confusion attacks. - Remediation: Add Zod schema validation with .input() to all procedures. ```typescript import { z } from 'zod'; export const userRouter = router({ getUser: publicProcedure .input(z.object({ userId: z.number().int().positive() })) .query(async ({ input }) => { return await db.user.findUnique({ where: { id: input.userId } }); }) }); ``` Learn more: https://shoulder.dev/learn/typescript/cwe-20/missing-input-validation - **TypeORM Entity Missing Validation** [HIGH]: TypeORM entities without class-validator decorators accept any data, enabling injection attacks and data integrity violations. - Remediation: Add class-validator decorators to all entity properties. ```typescript import { IsEmail, IsString, MinLength, Max } from 'class-validator'; @Entity() export class User { @Column() @IsEmail() email: string; @Column() @IsString() @MinLength(3) username: string; } ``` Learn more: https://shoulder.dev/learn/typescript/cwe-20/entity-validation-missing ### Typescript (7 rules) - **Business Logic Input Validation** [MEDIUM]: Detects business-critical values (discount, refund, quantity) used without validation. - Remediation: Validate business-critical inputs before use. ```javascript function validateDiscount(discount) { const value = parseFloat(discount); if (isNaN(value) || value < 0 || value > 100) { throw new Error('Discount must be 0-100'); } return value; } const validated = validateDiscount(req.body.discount); applyDiscount(validated); ``` Learn more: https://shoulder.dev/learn/javascript/cwe-20/business-logic-input-validation - **Unvalidated Business-Critical Values** [HIGH]: Detects business-critical values from user input used without validation. - Remediation: Use server-side prices and validate ranges before use. ```javascript const product = products.get(productId); const total = product.price * quantity; ``` Learn more: https://shoulder.dev/learn/javascript/cwe-20/unvalidated-business-values - **NestJS DTO Missing Validation Decorators** [HIGH]: DTOs without class-validator decorators allow unvalidated input to flow into the application, enabling injection and data corruption. - Remediation: Add class-validator decorators to DTO properties. ```typescript import { IsString, IsEmail, MinLength } from 'class-validator'; class CreateUserDTO { @IsString() @MinLength(3) username: string; @IsEmail() email: string; } ``` Learn more: https://shoulder.dev/learn/typescript/cwe-20/dto-missing-validation - **Prisma Missing Input Validation** [HIGH]: Passing req.body directly to Prisma where/data allows users to filter by unauthorized fields and bypass access controls. - Remediation: Validate and whitelist fields with Zod before Prisma queries. ```typescript import { z } from 'zod'; const getUsersInput = z.object({ role: z.enum(['user', 'moderator']).optional(), status: z.enum(['active', 'inactive']).optional() }); async function getUsers(req: Request) { const input = getUsersInput.parse(req.query); return await prisma.user.findMany({ where: input }); } ``` Learn more: https://shoulder.dev/learn/typescript/cwe-20/prisma-missing-input-validation - **tRPC Unsafe Context Usage** [HIGH]: Using unvalidated headers, cookies, or query params in context creation allows attackers to bypass authentication and impersonate users. - Remediation: Verify JWT signatures or use session libraries instead of trusting raw headers. ```typescript import { getServerSession } from 'next-auth'; export async function createContext({ req, res }: CreateNextContextOptions) { const session = await getServerSession(req, res, authOptions); return { user: session?.user ?? null, db }; } ``` Learn more: https://shoulder.dev/learn/typescript/cwe-20/context-injection - **tRPC Procedure Missing Input Validation** [HIGH]: tRPC procedures without .input() validation accept unvalidated payloads at runtime, enabling injection and type confusion attacks. - Remediation: Add Zod schema validation with .input() to all procedures. ```typescript import { z } from 'zod'; export const userRouter = router({ getUser: publicProcedure .input(z.object({ userId: z.number().int().positive() })) .query(async ({ input }) => { return await db.user.findUnique({ where: { id: input.userId } }); }) }); ``` Learn more: https://shoulder.dev/learn/typescript/cwe-20/missing-input-validation - **TypeORM Entity Missing Validation** [HIGH]: TypeORM entities without class-validator decorators accept any data, enabling injection attacks and data integrity violations. - Remediation: Add class-validator decorators to all entity properties. ```typescript import { IsEmail, IsString, MinLength, Max } from 'class-validator'; @Entity() export class User { @Column() @IsEmail() email: string; @Column() @IsString() @MinLength(3) username: string; } ``` Learn more: https://shoulder.dev/learn/typescript/cwe-20/entity-validation-missing ### Go (4 rules) - **Business Logic Input Validation** [MEDIUM]: Business-critical values (discount, quantity, refund) used without validation. - Remediation: Parse and validate business-critical values before use. ```go discount, err := strconv.ParseFloat(r.FormValue("discount"), 64) if err != nil || discount < 0 || discount > 100 { http.Error(w, "Invalid discount", 400) return } ``` Learn more: https://shoulder.dev/learn/go/cwe-20/input-validation - **Echo Missing Input Validation** [MEDIUM]: Echo endpoints accepting user input without struct validation. - Remediation: Use struct binding with validation tags. ```go type Input struct { Name string `json:"name" validate:"required"` } func handler(c echo.Context) error { var input Input if err := c.Bind(&input); err != nil { return c.JSON(400, map[string]string{"error": err.Error()}) } if err := c.Validate(&input); err != nil { return c.JSON(400, map[string]string{"error": err.Error()}) } return nil } ``` Learn more: https://shoulder.dev/learn/go/cwe-20/input-validation - **Fiber Missing Input Validation** [MEDIUM]: Fiber endpoints accepting user input without struct validation. - Remediation: Use BodyParser with struct validation tags. ```go type Input struct { Name string `json:"name" validate:"required"` } func handler(c *fiber.Ctx) error { var input Input if err := c.BodyParser(&input); err != nil { return c.Status(400).JSON(fiber.Map{"error": err.Error()}) } if err := validate.Struct(&input); err != nil { return c.Status(400).JSON(fiber.Map{"error": err.Error()}) } return nil } ``` Learn more: https://shoulder.dev/learn/go/cwe-20/input-validation - **Gin Missing Input Validation** [MEDIUM]: Gin endpoints accepting user input without struct binding validation. - Remediation: Use ShouldBindJSON with struct binding tags for validation. ```go type Input struct { Name string `json:"name" binding:"required,min=2"` Email string `json:"email" binding:"required,email"` } func handler(c *gin.Context) { var input Input if err := c.ShouldBindJSON(&input); err != nil { c.JSON(400, gin.H{"error": err.Error()}) return } } ``` Learn more: https://shoulder.dev/learn/go/cwe-20/input-validation ### Python (2 rules) - **FastAPI Missing Request Validation** [MEDIUM]: Detects FastAPI endpoints that accept raw Request objects instead of Pydantic models. This bypasses FastAPI's automatic validation and can lead to type confusion and injection vulnerabilities. - Remediation: Use Pydantic models instead of raw Request objects for automatic validation. ```python from pydantic import BaseModel, EmailStr, Field class UserCreate(BaseModel): username: str = Field(min_length=3, max_length=50) email: EmailStr @app.post("/users") async def create_user(user: UserCreate): return {"user": user} ``` Learn more: https://shoulder.dev/learn/python/cwe-20/missing-validation - **Business Logic Input Validation** [MEDIUM]: Detects business-critical input values (discount, refund, quantity, price) that are used in operations without proper validation. Missing validation can lead to financial fraud, inventory errors, or business logic bypass. - Remediation: Validate business-critical inputs with range constraints using Pydantic. ```python from pydantic import BaseModel, Field class DiscountRequest(BaseModel): discount: float = Field(..., ge=0, le=100) quantity: int = Field(..., gt=0) @app.post('/apply-discount') async def apply_discount_route(request: DiscountRequest): apply_discount(request.discount) ``` Learn more: https://shoulder.dev/learn/python/cwe-20/input-validation