Common Vulnerability Patterns

Understand and prevent the most frequent smart contract vulnerabilities. This guide covers vulnerability patterns frequently detected by BlockSecOps, along...

Last updated: January 14, 2026

Common Vulnerability Patterns

Understand and prevent the most frequent smart contract vulnerabilities.

Overview

This guide covers vulnerability patterns frequently detected by BlockSecOps, along with examples and fixes.


Critical Severity

Reentrancy

What it is: External calls that allow callback into the contract before state updates complete.

Vulnerable Code:

function withdraw() public {
    uint256 amount = balances[msg.sender];
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
    balances[msg.sender] = 0;  // State updated after call
}

Fixed Code:

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract Vault is ReentrancyGuard {
    function withdraw() public nonReentrant {
        uint256 amount = balances[msg.sender];
        balances[msg.sender] = 0;  // State updated before call
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success);
    }
}

Prevention:

  • Use ReentrancyGuard
  • Follow Checks-Effects-Interactions pattern
  • Update state before external calls

Access Control Missing

What it is: Functions that modify state without proper authorization checks.

Vulnerable Code:

function setAdmin(address newAdmin) public {
    admin = newAdmin;  // Anyone can call
}

Fixed Code:

function setAdmin(address newAdmin) public onlyOwner {
    require(newAdmin != address(0), "Invalid address");
    admin = newAdmin;
}

Prevention:

  • Use onlyOwner or role-based access
  • Validate new values
  • Consider timelocks for sensitive changes

Arbitrary External Call

What it is: User-controlled targets for external calls.

Vulnerable Code:

function execute(address target, bytes calldata data) public {
    target.call(data);  // Attacker controls target
}

Fixed Code:

mapping(address => bool) public allowedTargets;

function execute(address target, bytes calldata data) public onlyOwner {
    require(allowedTargets[target], "Target not allowed");
    (bool success, ) = target.call(data);
    require(success, "Call failed");
}

Prevention:

  • Whitelist allowed targets
  • Validate call data
  • Restrict to admin functions

High Severity

Integer Overflow/Underflow

What it is: Arithmetic that wraps around min/max values.

Vulnerable Code (pre-0.8.0):

pragma solidity ^0.7.0;

function transfer(address to, uint256 amount) public {
    balances[msg.sender] -= amount;  // Can underflow
    balances[to] += amount;          // Can overflow
}

Fixed Code:

pragma solidity ^0.8.0;  // Built-in overflow protection

function transfer(address to, uint256 amount) public {
    balances[msg.sender] -= amount;  // Reverts on underflow
    balances[to] += amount;          // Reverts on overflow
}

Prevention:

  • Use Solidity 0.8.0+
  • Use SafeMath for older versions
  • Validate inputs

Unchecked Return Value

What it is: Ignoring return values from external calls.

Vulnerable Code:

function transferTokens(address token, address to, uint256 amount) public {
    IERC20(token).transfer(to, amount);  // Return value ignored
}

Fixed Code:

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

function transferTokens(address token, address to, uint256 amount) public {
    SafeERC20.safeTransfer(IERC20(token), to, amount);
}

Prevention:

  • Use SafeERC20 for token transfers
  • Check return values with require
  • Use try/catch for external calls

Delegate Call to Untrusted Contract

What it is: Using delegatecall with user-controlled addresses.

Vulnerable Code:

function upgrade(address newImpl) public {
    (bool success, ) = newImpl.delegatecall(msg.data);
}

Fixed Code:

address public implementation;

function upgrade(address newImpl) public onlyOwner {
    require(newImpl != address(0));
    implementation = newImpl;
}

function _delegate(address impl) internal {
    (bool success, ) = impl.delegatecall(msg.data);
    require(success);
}

Prevention:

  • Use established upgrade patterns (UUPS, Transparent Proxy)
  • Restrict who can set implementation
  • Validate new implementation

Medium Severity

Front-Running Vulnerability

What it is: Transactions that can be observed and exploited by miners/bots.

Vulnerable Code:

function buyToken(uint256 maxPrice) public payable {
    uint256 price = getPrice();
    require(price <= maxPrice);
    // Attacker sees this and front-runs with price manipulation
}

Fixed Code:

function buyToken(uint256 maxPrice, uint256 deadline) public payable {
    require(block.timestamp <= deadline, "Expired");
    uint256 price = getPrice();
    require(price <= maxPrice, "Price too high");
    // Use commit-reveal for sensitive operations
}

Prevention:

  • Use commit-reveal schemes
  • Add deadline parameters
  • Use slippage protection

Timestamp Dependence

What it is: Relying on block.timestamp for critical logic.

Vulnerable Code:

function roll() public returns (uint256) {
    return uint256(keccak256(abi.encode(block.timestamp))) % 6;
}

Fixed Code:

// Use Chainlink VRF for randomness
function roll() public returns (uint256 requestId) {
    requestId = vrfCoordinator.requestRandomWords(...);
}

Prevention:

  • Use Chainlink VRF for randomness
  • Allow timestamp variance in time-based logic
  • Don't use timestamp as sole entropy source

Missing Input Validation

What it is: Not validating function parameters.

Vulnerable Code:

function setFee(uint256 newFee) public onlyOwner {
    fee = newFee;  // Could be set to 100% or higher
}

Fixed Code:

uint256 public constant MAX_FEE = 1000; // 10%
uint256 public constant FEE_DENOMINATOR = 10000;

function setFee(uint256 newFee) public onlyOwner {
    require(newFee <= MAX_FEE, "Fee too high");
    fee = newFee;
}

Prevention:

  • Validate all inputs
  • Use bounds checking
  • Define sensible limits

Low Severity

Floating Pragma

What it is: Using ^ in pragma allowing multiple compiler versions.

Issue:

pragma solidity ^0.8.0;  // Could be 0.8.0, 0.8.5, 0.8.20...

Fixed:

pragma solidity 0.8.20;  // Exact version

Why it matters:

  • Reproducible builds
  • Consistent behavior
  • Known security properties

Missing Events

What it is: State changes without event emission.

Issue:

function setOwner(address newOwner) public onlyOwner {
    owner = newOwner;  // No event
}

Fixed:

event OwnershipTransferred(address indexed previous, address indexed current);

function setOwner(address newOwner) public onlyOwner {
    emit OwnershipTransferred(owner, newOwner);
    owner = newOwner;
}

Why it matters:

  • Off-chain monitoring
  • Audit trail
  • User transparency

Unused Variables

What it is: Declared variables that are never used.

Issue:

function process() public {
    uint256 temp = 0;  // Never used
    // ...processing without temp
}

Fixed:

function process() public {
    // Remove unused variable
    // ...processing
}

Why it matters:

  • Gas waste
  • Code clarity
  • Potential logic errors

Vulnerability Categories

By Impact

Severity Examples
Critical Reentrancy, Access Control, Arbitrary Call
High Overflow, Unchecked Return, Delegate Call
Medium Front-running, Timestamp, Input Validation
Low Pragma, Events, Unused Variables

By Type

Type Examples
Access Control Missing checks, Privilege escalation
Arithmetic Overflow, Division by zero, Precision loss
External Calls Reentrancy, Unchecked returns
Data Validation Missing validation, Type confusion

Next Steps