Security 10 min read

Smart Contract Security: The 10 Bugs That Drain Protocols

Reentrancy is the famous one. These are the nine others that actually show up in audits — with the code patterns that prevent them.

S
ShipWeb3 Admin June 11, 2026 · 4,131 views
Smart Contract Security: The 10 Bugs That Drain Protocols

Every one of these has cost a real protocol real money. None of them are exotic.

1. Reentrancy

External call before state update. Use checks-effects-interactions ordering, and add a reentrancy guard on anything touching balances.

2. Unchecked external call return values

Some ERC-20s return false instead of reverting. Some return nothing at all. Use SafeERC20 and stop assuming transfers succeed.

3. Price oracle manipulation

Reading spot price from an AMM pool is a flash-loan invitation. Use a TWAP, or better, a manipulation-resistant oracle with staleness checks.

4. Rounding in the protocol's disfavour

Integer division truncates. If your rounding consistently favours the user, someone will loop it a million times. Round in favour of the protocol on every share calculation.

5. Missing access control

An admin function without a modifier. It sounds too simple to happen and it happens constantly. Test that every privileged function reverts for a random caller.

6. Uninitialised proxy implementations

Deploy a proxy, forget to call initialize, and someone else calls it and owns your contract. Initialise in the same transaction as deployment.

7. First-depositor share inflation

In vaults, the first depositor can donate assets to skew the share ratio and steal from the second. Mint dead shares at initialisation.

8. Signature replay

Signatures valid across chains or reusable within one. Include a nonce, a deadline, and the chain ID in the signed payload.

9. Delegatecall to untrusted targets

Delegatecall runs foreign code in your storage context. If the target is user-supplied, you have handed over the contract.

10. Denial of service by unbounded loops

Iterating an array that users can grow means eventually the function exceeds the gas limit and nothing works again. Use pull patterns and paginate.

How to actually catch these

Write invariant tests — properties that must hold no matter what sequence of calls happens. Run Slither on every commit. Fuzz your arithmetic. Then get an audit, because you will still have missed something.

S
ShipWeb3 Admin

Web3 developer building Telegram Mini Apps, bots and on-chain products.

Skip the build

Want this already working?

The code behind these articles is available as complete, deployable projects.