← Back to Blog

Solidity Security Checklist: 10 Vulnerabilities to Fix Before Mainnet Deployment

2026-04-15 solidity security checklist mainnet audit smart-contract best-practices 2026

Deploying a smart contract to mainnet is a one-way door. Unlike traditional software, you can't push a hotfix if a vulnerability is exploited. Every DeFi protocol that lost millions learned the same lesson the hard way.

This checklist covers the 10 most common (and most costly) vulnerability classes every Solidity developer should verify before going live. For each one, we explain what to look for and how automated scanning can help catch it.


1. Reentrancy

What it is: An external contract call is made before internal state is updated, allowing the callee to re-enter the function and drain funds.

Classic pattern:

// VULNERABLE
function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount);
    (bool ok,) = msg.sender.call{value: amount}(""); // external call first
    balances[msg.sender] -= amount;                   // state updated after
}

Fix: Follow the Checks-Effects-Interactions (CEI) pattern. Update state before making any external call.

Detection: Slither's reentrancy-eth and reentrancy-no-eth detectors catch this reliably. Mythril also models it symbolically.


2. Access Control Missing or Misconfigured

What it is: Sensitive functions (mint, pause, upgradeProxy, emergencyWithdraw) lack onlyOwner, onlyRole, or equivalent guards.

Common mistake:

// Anyone can call this
function setTreasury(address newTreasury) external {
    treasury = newTreasury;
}

Fix: Use OpenZeppelin's AccessControl or Ownable. Explicitly restrict privileged functions. Consider a multi-sig or timelock for critical operations.

Detection: Slither's missing-zero-check and Semgrep rules for unguarded state-changing functions. AI analysis is particularly effective here for finding logical access control gaps that pattern-matching misses.


3. Integer Overflow / Underflow

What it is: In Solidity < 0.8, arithmetic wraps silently. uint256(0) - 1 becomes 2^256 - 1.

Pre-0.8 risk:

// Solidity 0.7 — wraps to 2^256-1
uint256 public balance;
function decrement() external {
    balance -= 1; // underflows if balance == 0
}

Fix: Upgrade to Solidity ≥ 0.8 (overflow/underflow reverts by default), or use SafeMath on older versions.

Detection: Slither's integer-overflow-and-underflow detectors. Also flagged by Aderyn on older compiler targets.


4. Uninitialized Storage Pointers

What it is: A local struct declared without memory or storage keyword points to slot 0 by default, potentially overwriting critical state.

Fix: Always specify memory or storage explicitly for struct/array local variables.

Detection: Slither's uninitialized-storage detector.


5. Tx.origin Authentication

What it is: Using tx.origin for authorization instead of msg.sender makes the contract vulnerable to phishing attacks where a malicious contract relays a transaction.

// VULNERABLE
require(tx.origin == owner, "Not authorized");

// CORRECT
require(msg.sender == owner, "Not authorized");

Detection: Semgrep and Slither both flag tx.origin usage in authentication context.


6. Oracle Price Manipulation

What it is: Relying on a single DEX spot price (e.g., a Uniswap v2 reserve ratio) as a price oracle. Attackers use flash loans to manipulate the price within a single transaction.

High-risk pattern:

// Single-source spot price — manipulable with flash loan
function getPrice() public view returns (uint256) {
    (uint112 reserve0, uint112 reserve1,) = pair.getReserves();
    return reserve1 * 1e18 / reserve0;
}

Fix: Use TWAP (Time-Weighted Average Price) oracles, Chainlink price feeds, or multi-source aggregation with deviation checks.

Detection: AI-based analysis is best here — static analyzers often miss the semantic risk. Semgrep rules can flag getReserves() calls used for pricing.


7. Unchecked Return Values

What it is: ERC-20 transfer() and approve() don't always revert on failure — some return false instead. Ignoring the return value means a silent failure.

// VULNERABLE — return value ignored
token.transfer(recipient, amount);

// CORRECT
require(token.transfer(recipient, amount), "Transfer failed");
// Or use SafeERC20 from OpenZeppelin

Fix: Use OpenZeppelin's SafeERC20 wrapper, which handles both reverting and non-reverting ERC-20 implementations.

Detection: Slither's unchecked-transfer detector.


8. Delegate Call to Untrusted Contracts

What it is: delegatecall executes code from an external address in the context of the calling contract — using its storage, ETH balance, and msg.sender. Passing user-controlled addresses to delegatecall is extremely dangerous.

Fix: Never delegatecall to addresses that aren't trusted, immutable, or validated. In upgradeable proxies, ensure only authorized parties can change the implementation address.

Detection: Slither's controlled-delegatecall and delegatecall-loop detectors.


9. Timestamp Dependence

What it is: Using block.timestamp for randomness, lock periods, or sensitive logic. Miners (or validators post-merge) can manipulate timestamps within a ~15 second window.

Risky pattern:

// block.timestamp can be slightly manipulated
require(block.timestamp >= unlockTime, "Too early");
uint256 random = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender)));

Fix: For randomness, use Chainlink VRF. For time-based locks, the 15-second manipulation window is usually acceptable for durations > 1 minute, but never rely on it for precise timing.

Detection: Slither's timestamp detector. AI analysis can identify semantic risk (e.g., is the timestamp used for randomness vs. a reasonable time gate?).


10. Front-Running (MEV) Vulnerabilities

What it is: Transactions in the mempool are public. Attackers (or bots) can observe your transaction and submit their own with higher gas, executing first. This affects token swaps, auctions, NFT mints, and commit-reveal schemes.

Common targets:
- Slippage-free swap calls
- Dutch auction bids
- On-chain reveal of secrets hashed in commit phase

Fix: Implement slippage parameters (minAmountOut), use commit-reveal patterns, or consider private mempools (Flashbots Protect) for sensitive transactions.

Detection: Primarily AI and manual review territory — static analysis has limited visibility into economic MEV dynamics.


How to Run This Checklist

Manually reviewing all 10 categories for a non-trivial contract is time-consuming and error-prone. A good approach:

  1. Automated scan first — run Slither, Semgrep, Mythril, and Aderyn to catch the mechanical issues (reentrancy, integer overflow, unchecked returns, tx.origin, etc.)
  2. AI analysis — for semantic issues like oracle manipulation and business logic flaws that pattern-matching misses
  3. Manual review — especially for access control logic and MEV exposure
  4. Test suite — property-based and fuzz testing with Foundry or Hardhat

ContractScan runs all five engines (Slither, Semgrep, Mythril, Aderyn, AI) in parallel and produces a structured vulnerability report with severity ratings and suggested fixes. A full scan covers all 10 categories above in under two minutes — no setup, no CLI, no local Solidity toolchain required.


Quick Reference Table

# Vulnerability Severity Auto-Detectable
1 Reentrancy Critical Yes (Slither, Mythril)
2 Missing Access Control High Yes (Slither, Semgrep, AI)
3 Integer Overflow/Underflow High Yes (Slither, Aderyn)
4 Uninitialized Storage High Yes (Slither)
5 Tx.origin Auth Medium Yes (Slither, Semgrep)
6 Oracle Manipulation Critical Partial (AI, Semgrep)
7 Unchecked Return Values Medium Yes (Slither)
8 Dangerous Delegatecall Critical Yes (Slither)
9 Timestamp Dependence Low-Med Yes (Slither)
10 Front-Running / MEV Varies Partial (AI, manual)

Deploying to mainnet before running this checklist is like shipping without tests. Even if you pass every item manually, a second pair of automated eyes is worth the five minutes it takes — because attackers only need to find one gap you missed.

Important Notes

This post is for informational and educational purposes only. It does not constitute financial, legal, or investment advice. The security analysis provided is based on available data and automated tools, which may not capture all potential vulnerabilities. Always conduct a professional audit before deploying smart contracts.

Scan your contract now
Slither + AI analysis — Unlimited quick scans. No signup required.
Try Free Scan →