Input Validation
The process of verifying that user-supplied data meets expected formats and constraints before processing, preventing injection attacks and logic errors.
Input validation is a fundamental security practice that verifies user-supplied data meets expected formats, types, and constraints before the application processes it. In both smart contracts and web applications, failing to validate inputs can lead to critical vulnerabilities including injection attacks, integer overflows, unauthorized access, and logic errors. Proper input validation is the first line of defense against many common attack vectors.
Why Input Validation Matters
Without validation, attackers can supply malicious inputs:
1// VULNERABLE: No validation2function transfer(address to, uint256 amount) external {3 balances[msg.sender] -= amount;4 balances[to] += amount;5}67// Attack vectors:8// - to = address(0) → tokens lost forever9// - amount > balance → underflow (pre-0.8.0)10// - to = msg.sender → self-transfer issues
Smart Contract Input Validation
Address Validation
1function setRecipient(address _recipient) external {2 require(_recipient != address(0), "Zero address");3 require(_recipient != address(this), "Cannot be self");4 recipient = _recipient;5}
Amount Validation
1function deposit(uint256 amount) external {2 require(amount > 0, "Zero amount");3 require(amount <= maxDeposit, "Exceeds max");4 require(amount >= minDeposit, "Below min");5 // Process deposit6}
Array Validation
1function batchTransfer(address[] calldata recipients, uint256[] calldata amounts) external {2 require(recipients.length == amounts.length, "Length mismatch");3 require(recipients.length > 0, "Empty array");4 require(recipients.length <= MAX_BATCH, "Too many recipients");56 for (uint256 i = 0; i < recipients.length; i++) {7 require(recipients[i] != address(0), "Zero address in batch");8 _transfer(recipients[i], amounts[i]);9 }10}
Bounds Checking
1function setFee(uint256 _fee) external onlyOwner {2 require(_fee <= MAX_FEE, "Fee too high"); // e.g., MAX_FEE = 1000 (10%)3 fee = _fee;4}56function setIndex(uint256 _index) external {7 require(_index < array.length, "Index out of bounds");8 currentIndex = _index;9}
Web Application Input Validation
TypeScript/JavaScript
1function validateAddress(address: string): boolean {2 return /^0x[a-fA-F0-9]{40}$/.test(address);3}45function validateAmount(amount: string): boolean {6 const num = parseFloat(amount);7 return !isNaN(num) && num > 0 && num <= MAX_AMOUNT;8}910// Express.js middleware11function validateTransferInput(req, res, next) {12 const { to, amount } = req.body;1314 if (!validateAddress(to)) {15 return res.status(400).json({ error: 'Invalid address' });16 }17 if (!validateAmount(amount)) {18 return res.status(400).json({ error: 'Invalid amount' });19 }2021 next();22}
Sanitization vs Validation
Validation: Check if input is acceptable, reject if not
1if (!isValidEmail(email)) {2 throw new Error('Invalid email');3}
Sanitization: Transform input to safe format
1import DOMPurify from 'dompurify';2const safeHtml = DOMPurify.sanitize(userInput);
Both are needed—validate first, then sanitize if accepting.
Common Validation Patterns
Whitelist vs Blacklist
1// WEAK: Blacklist (blocks known bad)2function isValidInput(input: string): boolean {3 const blacklist = ['<script>', 'javascript:', 'onerror'];4 return !blacklist.some(bad => input.includes(bad));5}67// STRONG: Whitelist (allows known good)8function isValidInput(input: string): boolean {9 return /^[a-zA-Z0-9\s]+$/.test(input); // Only alphanumeric10}
Whitelisting is preferred—it's secure by default.
Type Coercion Safety
1// DANGEROUS: Implicit conversion2const amount = Number(userInput); // "123abc" → 12334// SAFER: Strict parsing with validation5function parseAmount(input: string): number {6 if (!/^\d+(\.\d+)?$/.test(input)) {7 throw new Error('Invalid number format');8 }9 return parseFloat(input);10}
Validation Libraries
Solidity
Use modifiers for reusable validation:
1modifier validAddress(address _addr) {2 require(_addr != address(0), "Invalid address");3 _;4}56modifier validAmount(uint256 _amount) {7 require(_amount > 0 && _amount <= MAX, "Invalid amount");8 _;9}1011function transfer(address to, uint256 amount)12 external13 validAddress(to)14 validAmount(amount)15{16 // Logic here17}
TypeScript
1import { z } from 'zod';23const TransferSchema = z.object({4 to: z.string().regex(/^0x[a-fA-F0-9]{40}$/),5 amount: z.number().positive().max(1000000),6 memo: z.string().max(256).optional()7});89function validateTransfer(data: unknown) {10 return TransferSchema.parse(data); // Throws on invalid11}
Input Validation in DeFi
Price/Rate Validation
1function setPrice(uint256 _price) external onlyOracle {2 require(_price > 0, "Zero price");3 require(_price <= MAX_PRICE, "Price too high");45 // Sanity check against last price6 if (lastPrice > 0) {7 uint256 change = diff(_price, lastPrice) * 100 / lastPrice;8 require(change <= MAX_CHANGE, "Price change too large");9 }1011 lastPrice = _price;12}
Slippage Parameters
1function swap(uint256 amountIn, uint256 minAmountOut) external {2 require(minAmountOut > 0, "Min output zero");34 uint256 amountOut = calculateOutput(amountIn);5 require(amountOut >= minAmountOut, "Slippage exceeded");67 // Execute swap8}
Audit Checklist
When auditing input validation:
- All external function parameters validated
- Zero address checks on address inputs
- Bounds checking on numeric inputs
- Array length validation (non-zero, max length)
- String length limits
- Type-appropriate validation (addresses, amounts, IDs)
- Whitelist approach over blacklist
- Consistent validation across similar functions
Input validation is a foundational security practice that prevents entire classes of vulnerabilities. Always validate at the earliest point and never trust user input, regardless of its source.
Related Terms
Cross-Site Scripting (XSS)
A web vulnerability where attackers inject malicious scripts into web applications, enabling theft of user data or unauthorized actions.
Access Control
Security mechanisms that restrict which addresses can call specific functions in a smart contract, preventing unauthorized actions.
Solidity
The primary programming language for writing smart contracts on Ethereum and EVM-compatible blockchains.
Modifier
Reusable code blocks in Solidity that modify function behavior, commonly used for access control and input validation.
Need expert guidance on Input Validation?
Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.
Get a Quote
