Kelid Majazi Tabadol Kelid Majazi Tabadol KMT · CORE
فا
Get a consultation

Smart contract security: 8 common vulnerabilities and how to prevent them

Smart contract security: 8 common vulnerabilities and how to prevent them

Smart contracts are programs that directly control real assets. Unlike ordinary software, code deployed on a public chain is visible to everyone and attackers have all the time they need to study it. That is why security must be guaranteed before deployment.

1. Reentrancy

When a contract sends funds to an external address before updating its internal state, an attacking contract can call the withdraw function again within the same call.

// unsafe
function withdraw() external {
    uint amount = balances[msg.sender];
    (bool ok,) = msg.sender.call{value: amount}("");
    require(ok);
    balances[msg.sender] = 0;   // too late!
}

// safe: Checks-Effects-Interactions
function withdraw() external nonReentrant {
    uint amount = balances[msg.sender];
    balances[msg.sender] = 0;
    (bool ok,) = msg.sender.call{value: amount}("");
    require(ok);
}

2. Broken access control

Sensitive functions such as mint, pause or ownership transfer must be limited to specific roles. Role-based patterns and multisig for administrative operations are essential.

3. Overflow and arithmetic errors

In languages or versions without automatic overflow checks, unchecked addition and subtraction can turn a balance into a nonsensical number. The order of multiplication and division in fee calculations also causes rounding errors.

4. Price-oracle manipulation

Relying on the spot price of a small liquidity pool lets an attacker move the price with a flash loan. Use decentralised oracles and time-weighted average prices (TWAP).

5. Front-running

Pending transactions are visible in the public mempool. Commit–reveal schemes and a maximum slippage limit reduce the impact of this attack.

6. Timestamp dependence and weak randomness

Values such as block time are predictable or partly manipulable and must not be the source of randomness for lotteries or games.

7. Unsafe upgrade logic

Proxy contracts that are not initialised correctly, or whose storage layout changes between versions, can hand control of the contract to an attacker.

8. Denial of service through unbounded loops

A loop over an array that users can grow may push execution cost beyond the limit and lock the contract.

A secure development process

  1. Threat modelling and defining assets and roles before coding
  2. Using standard, battle-tested libraries
  3. Unit tests, fuzz tests and edge-case coverage
  4. Static analysis with automated tools
  5. Independent audit and fixing findings before deployment
  6. Gradual rollout on testnet, a bug bounty and post-deployment monitoring
An audit always costs less than a successful attack.
Share: 𝕏