Blockchain & Web3 Security — Deep Dive Training
Blockchain & Web3 Security — Deep Dive Training
CIPHER Domain Training — Blockchain, Smart Contract Auditing, DeFi Security Last updated: 2026-03-14
Table of Contents
- Smart Contract Vulnerability Taxonomy
- Solidity Security Patterns
- DeFi-Specific Attack Vectors
- Bridge Vulnerabilities
- Wallet Security & Key Management
- Auditing Methodology
- Tooling Reference
- SWC Registry Reference
- Historical Exploit Database
1. Smart Contract Vulnerability Taxonomy
1.1 Reentrancy (SWC-107)
Classification: Critical | CWE-841 (Improper Enforcement of Behavioral Workflow)
Reentrancy occurs when an external call allows a malicious contract to recursively re-enter the calling contract before state updates complete. The attacker's fallback/receive function hijacks execution flow, draining funds or corrupting state.
Subtypes:
| Type | Description | Example |
|---|---|---|
| Single-Function | Recursive call to the same vulnerable function | The DAO (2016) — $60M ETH drained |
| Cross-Function | Reentry targets a different function sharing the same state | Functions sharing a balance mapping |
| Cross-Contract | Reentry targets a different contract that shares state | Lending protocols with shared registries |
| Cross-Chain | Exploiting message-passing between chains before state finality | Bridge relay reentrancy |
| Read-Only | Reentry during a view function that returns stale state to a third contract | Curve/Vyper exploit (2023, $69.3M) |
Attack Pattern:
// VULNERABLE — state update after external call
function withdraw() public {
uint bal = balances[msg.sender];
(bool sent, ) = msg.sender.call{value: bal}(""); // external call FIRST
require(sent, "Failed");
balances[msg.sender] = 0; // state update AFTER — too late
}
// Attacker's contract
receive() external payable {
if (address(target).balance >= 1 ether) {
target.withdraw(); // re-enter before balance zeroed
}
}
Prevention:
- Checks-Effects-Interactions (CEI): Update state BEFORE external calls
- Reentrancy guards: OpenZeppelin
ReentrancyGuard(mutex lock vianonReentrantmodifier) - Pull-over-push: Let users withdraw rather than pushing funds
- Gas limitation:
transfer()limits to 2300 gas (insufficient for reentry) — but this is brittle post-EIP-1884
Detection: Slither detector reentrancy-eth, reentrancy-no-eth, reentrancy-benign; Mythril SWC-107 check; Manticore symbolic analysis.
Real-World Impact: 60+ documented reentrancy exploits from 2016-2025, including The DAO, SpankChain, Lendf.Me, Cream Finance, Curve, Conic Finance, EraLend, and GMX.
1.2 Integer Overflow & Underflow (SWC-101)
Classification: High | CWE-190/CWE-191
EVM integers are fixed-size (uint256, uint8, etc.). Pre-Solidity 0.8.0, arithmetic silently wraps: uint8(255) + 1 = 0, uint8(0) - 1 = 255.
Attack Pattern:
// Pre-0.8.0: underflow bypasses timelock
mapping(address => uint256) public lockTime;
function increaseLockTime(uint256 _time) public {
lockTime[msg.sender] += _time; // overflow wraps to small value
}
// Attacker calls with _time = type(uint256).max - lockTime + 1
// Result: lockTime wraps to 0, bypassing timelock
Prevention:
- Solidity >= 0.8.0: Built-in overflow/underflow checks (revert on wrap)
- SafeMath library: For contracts on older compilers
unchecked {}blocks: Used intentionally for gas optimization — audit every use
Note: Solidity 0.8+ made this largely historical for new contracts, but legacy contracts and unchecked blocks remain attack surface.
1.3 Access Control Failures (SWC-105, SWC-106, SWC-100)
Classification: Critical | CWE-284
Missing or incorrect access control on privileged functions — initialization, ownership transfer, fund withdrawal, contract destruction, parameter updates.
Common Patterns:
| Failure | SWC | Description |
|---|---|---|
| Default visibility | SWC-100 | Functions default public — internal logic exposed |
| Unprotected withdrawal | SWC-105 | No onlyOwner on fund extraction |
| Unprotected selfdestruct | SWC-106 | Anyone can destroy the contract |
| Wrong constructor name | SWC-118 | Typo makes constructor a regular callable function |
| Missing modifier | — | Admin functions without access checks |
| Uninitialized proxy | — | initialize() callable by anyone post-deployment |
Attack Pattern:
// VULNERABLE — anyone can call
function setOwner(address _newOwner) public {
owner = _newOwner;
}
// VULNERABLE — Parity wallet: constructor was a regular function
function initWallet(address[] _owners, uint _required) public {
// no check if already initialized
m_owners = _owners;
}
Prevention:
- Explicit visibility on every function (
external,public,internal,private) - OpenZeppelin
Ownable,AccessControl, orAccessControlEnumerable - Role-based access with separation of duties (admin vs. operator vs. guardian)
- Initializer guards for proxy patterns:
initializermodifier from OpenZeppelin - Two-step ownership transfer (
Ownable2Step)
1.4 Flash Loan Attacks
Classification: Critical | No SWC (DeFi-specific)
Flash loans enable uncollateralized borrowing within a single transaction. Attackers use massive capital (often $100M+) to manipulate prices, drain pools, or exploit governance — all atomically.
Attack Anatomy:
1. Borrow $100M via flash loan (Aave, dYdX, Balancer)
2. Manipulate target (price oracle, governance vote, liquidity pool)
3. Extract profit from manipulated state
4. Repay flash loan + fee
5. Net profit in single transaction — no capital required
Common Flash Loan Attack Chains:
| Vector | Mechanism |
|---|---|
| Price manipulation | Swap large amount on low-liquidity DEX to skew spot price; borrow against inflated collateral |
| Governance attack | Borrow governance tokens, vote on malicious proposal, execute in same block |
| Liquidity drain | Manipulate pool ratios to extract disproportionate value |
| Arbitrage exploitation | Exploit price differences across venues amplified by borrowed capital |
Real-World Examples:
- Beanstalk ($181M, 2022): Flash-loaned governance tokens to pass malicious proposal
- Yieldblox ($10.97M, 2026): Inflated illiquid collateral USTRY 100x via DEX manipulation
- Numerous Pancake/Burger/Value DeFi exploits (2020-2021)
Prevention:
- TWAP oracles: Time-weighted average prices resist single-block manipulation
- Chainlink/decentralized oracles: External price feeds not manipulable within one transaction
- Governance timelocks: Proposals require multi-block delay between vote and execution
- Flash loan-resistant checks: Compare spot price to oracle; reject > X% deviation
- Protocol-level circuit breakers: Pause on anomalous volume or price movement
1.5 Oracle Manipulation
Classification: Critical | No SWC (DeFi-specific)
Protocols relying on on-chain price data (AMM spot prices, single-source feeds) are vulnerable to price manipulation. Attackers distort the oracle's reported price to trigger favorable protocol actions.
Attack Vectors:
| Vector | Description |
|---|---|
| Spot price manipulation | Large swap on thin-liquidity DEX moves reported price |
| TWAP manipulation | Sustained trading over observation window to shift time-weighted price |
| Oracle front-running | Exploit delay between real price change and oracle update |
| Stale price exploitation | Use outdated oracle data when market has moved significantly |
| Multi-oracle arbitrage | Exploit price discrepancy between oracles used by different protocols |
Prevention:
- Use Chainlink or equivalent decentralized oracle networks with multiple data sources
- Implement TWAP with sufficiently long observation windows
- Validate oracle freshness: reject prices older than N blocks
- Circuit breakers: cap maximum price change per update
- Never use AMM spot price as sole oracle source
- Sanity bounds: reject prices outside expected range
Real-World: Aave ($27.78M, 2026) — misconfigured oracle cap triggered cascade liquidations; Mango Markets ($114M, 2022) — attacker manipulated MNGO perp price on low-liquidity market.
1.6 Front-Running & MEV (SWC-114)
Classification: High | CWE-362
Transactions in the public mempool are visible before inclusion in a block. Miners/validators and MEV searchers can reorder, insert, or censor transactions for profit.
Attack Types:
| Type | Mechanism |
|---|---|
| Front-running | Submit competing tx with higher gas to execute before victim |
| Back-running | Execute immediately after a target tx to capture arbitrage |
| Sandwich attack | Front-run + back-run a swap: buy before victim (raise price), victim buys at inflated price, attacker sells after |
| Time-bandit attack | Reorg blocks to extract past MEV (theoretical at scale) |
| Transaction censorship | Validators selectively exclude transactions |
Sandwich Attack Flow:
1. Attacker sees pending swap: Buy 100 ETH worth of TOKEN_X
2. Attacker front-runs: Buys TOKEN_X (price rises)
3. Victim's tx executes at higher price (worse rate)
4. Attacker back-runs: Sells TOKEN_X at elevated price
5. Attacker profits from the price impact of victim's trade
Prevention:
- Commit-reveal schemes: Hash commitment in tx1, reveal in tx2
- Private mempools: Flashbots Protect, MEV Blocker, private relays
- Slippage limits: Maximum acceptable price deviation on swaps
- Batch auctions: Aggregate orders and execute at uniform price (CoW Protocol)
- Encrypted mempools: Threshold encryption of pending transactions
- On-chain order books: Limit orders less susceptible than market orders
1.7 Delegatecall Vulnerabilities (SWC-112)
Classification: Critical | CWE-829
delegatecall executes external code in the caller's storage context. Critical for proxy patterns but dangerous when the target is untrusted or storage layouts mismatch.
Attack Patterns:
- Storage collision: Proxy and implementation have different storage layouts — delegatecall corrupts proxy state
- Untrusted delegatecall target: Attacker-controlled address executes arbitrary code in victim's context
- Uninitialized proxy: Implementation's
initialize()callable on proxy, overwriting owner
Real-World: Parity multi-sig wallet hack (2017) — delegatecall to library allowed attacker to become owner and selfdestruct, freezing $150M+ ETH.
Prevention:
- Only
delegatecallto trusted, audited implementation contracts - Use EIP-1967 standard proxy storage slots to prevent collision
- OpenZeppelin
TransparentUpgradeableProxyorUUPSUpgradeable - Storage gap pattern in base contracts for future upgrades
- Lock
initialize()on implementation contract itself
1.8 Denial of Service (SWC-113, SWC-128)
Classification: High | CWE-400
Contracts rendered unusable through resource exhaustion, forced reverts, or gas limit abuse.
Patterns:
| Pattern | SWC | Description |
|---|---|---|
| Failed call DoS | SWC-113 | External call failure reverts entire transaction |
| Gas limit DoS | SWC-128 | Unbounded loop over growing array exceeds block gas limit |
| Griefing | SWC-126 | Insufficient gas forwarding causes subcall failure |
| Self-destruct forcing | SWC-132 | Force ETH into contract, breaking balance assumptions |
| Storage bloat | — | Attacker inflates contract storage to make operations expensive |
Prevention:
- Pull-over-push payment pattern
- Bound all loops and iterations
- Paginate operations on dynamic arrays
- Never rely on
address(this).balancefor logic - Handle external call failures gracefully (don't revert on failed send)
1.9 Signature & Cryptographic Weaknesses (SWC-117, SWC-121, SWC-122)
Classification: High
| Weakness | SWC | Description |
|---|---|---|
| Signature malleability | SWC-117 | ECDSA s value can be flipped; same message, different signature |
| Signature replay | SWC-121 | Valid signature reused across transactions or chains |
| Missing verification | SWC-122 | ecrecover returns address(0) on invalid sig — not checked |
Prevention:
- Use OpenZeppelin
ECDSA.recover()(handles malleability, zero-address check) - Include
nonce,chainId,contract addressin signed messages (EIP-712) - Invalidate used signatures (nonce increment or mapping)
- EIP-191 prefix for personal sign to prevent cross-context replay
1.10 Randomness Vulnerabilities (SWC-120)
Classification: High | CWE-330
On-chain randomness sources (block.timestamp, block.prevrandao, blockhash) are predictable or influenceable by validators.
Prevention:
- Chainlink VRF: Verifiable random function with cryptographic proof
- Commit-reveal: Users commit hash of choice, reveal after commitment period
- RANDAO + VDF: Post-merge
prevrandaois better but still validator-influenceable for high-value outcomes
1.11 Unchecked Return Values (SWC-104)
Classification: Medium | CWE-252
Low-level calls (call, send, delegatecall) return a boolean success flag. If unchecked, failed transfers silently continue execution.
// VULNERABLE
payable(msg.sender).send(amount); // returns false on failure, doesn't revert
// SAFE
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Transfer failed");
1.12 tx.origin Authentication (SWC-115)
Classification: High | CWE-346
tx.origin returns the EOA that initiated the transaction chain. Using it for authorization allows phishing: attacker's contract calls victim's contract, and tx.origin still equals the victim's address.
// VULNERABLE
require(tx.origin == owner); // phishable
// SAFE
require(msg.sender == owner); // checks immediate caller
1.13 Timestamp Dependence (SWC-116)
Classification: Medium
block.timestamp can be slightly manipulated by validators (typically +/- 15 seconds). Dangerous for time-sensitive logic (auctions, lotteries, timelocks).
Prevention: Use block numbers for longer intervals; add tolerance buffers; avoid strict equality checks on timestamps.
1.14 Storage & Memory Safety
| Vulnerability | SWC | Description |
|---|---|---|
| Uninitialized storage pointer | SWC-109 | Local storage variable points to slot 0, corrupting state |
| Arbitrary storage write | SWC-124 | Dynamic array length manipulation to write to any storage slot |
| Variable shadowing | SWC-119 | Inherited state variable shadowed by child — wrong variable modified |
| Hash collision | SWC-133 | abi.encodePacked with variable-length args produces collisions |
2. Solidity Security Patterns
2.1 Checks-Effects-Interactions (CEI)
The foundational pattern for preventing reentrancy and state inconsistency:
function withdraw(uint amount) external {
// CHECKS — validate preconditions
require(balances[msg.sender] >= amount, "Insufficient");
// EFFECTS — update state
balances[msg.sender] -= amount;
// INTERACTIONS — external calls last
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "Transfer failed");
}
2.2 Pull-Over-Push Payments
Never push funds in a loop. Let recipients withdraw:
// DANGEROUS — one failed send blocks everyone
function payAll() external {
for (uint i = 0; i < recipients.length; i++) {
payable(recipients[i]).transfer(amounts[i]); // DoS vector
}
}
// SAFE — pull pattern
mapping(address => uint) public pendingWithdrawals;
function withdraw() external {
uint amount = pendingWithdrawals[msg.sender];
pendingWithdrawals[msg.sender] = 0;
payable(msg.sender).transfer(amount);
}
2.3 Reentrancy Guard
abstract contract ReentrancyGuard {
uint256 private _status = 1; // NOT_ENTERED
modifier nonReentrant() {
require(_status != 2, "ReentrancyGuard: reentrant call");
_status = 2; // ENTERED
_;
_status = 1; // NOT_ENTERED
}
}
2.4 Access Control Patterns
// Basic ownership
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
// Role-based (OpenZeppelin AccessControl)
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {
_mint(to, amount);
}
// Two-step ownership transfer (prevents fat-finger)
function transferOwnership(address newOwner) external onlyOwner {
pendingOwner = newOwner;
}
function acceptOwnership() external {
require(msg.sender == pendingOwner);
owner = pendingOwner;
}
2.5 Safe External Calls
// Use OpenZeppelin SafeERC20 for token transfers
using SafeERC20 for IERC20;
token.safeTransfer(recipient, amount); // reverts on failure
// Check return values on low-level calls
(bool success, bytes memory data) = target.call(payload);
require(success, "Call failed");
2.6 Proxy Upgrade Safety
// Storage gap for upgradeable base contracts
contract BaseV1 is Initializable {
uint256 public value;
uint256[49] private __gap; // reserve 49 slots for future variables
}
// Initializer guard
function initialize(address _owner) external initializer {
owner = _owner;
}
// UUPS: restrict upgrades
function _authorizeUpgrade(address newImpl) internal override onlyOwner {}
2.7 Secure Randomness
// Use Chainlink VRF v2+
function requestRandom() external returns (uint256 requestId) {
requestId = COORDINATOR.requestRandomWords(
keyHash, subscriptionId, requestConfirmations,
callbackGasLimit, numWords
);
}
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)
internal override {
// use randomWords[0] for game logic
}
2.8 Emergency Controls
// Circuit breaker (OpenZeppelin Pausable)
function transfer(address to, uint amount) external whenNotPaused {
_transfer(msg.sender, to, amount);
}
// Emergency withdrawal with timelock
function emergencyWithdraw() external onlyGuardian {
require(block.timestamp >= emergencyTimestamp + DELAY);
// drain to safe address
}
// Rate limiting
uint256 public lastAction;
uint256 public constant COOLDOWN = 1 hours;
modifier rateLimited() {
require(block.timestamp >= lastAction + COOLDOWN);
lastAction = block.timestamp;
_;
}
3. DeFi-Specific Attack Vectors
3.1 Lending Protocol Attacks
| Vector | Description | Example |
|---|---|---|
| Price oracle manipulation | Inflate collateral value via DEX manipulation, borrow against it | Mango Markets ($114M) |
| Flash loan + oracle | Borrow large sum, manipulate oracle, borrow against inflated collateral, repay flash loan | Cream Finance, Venus |
| Liquidation cascades | Trigger mass liquidations by manipulating price feeds | Aave wstETH ($27.78M, 2026) |
| Interest rate manipulation | Exploit utilization-based rate curves | Compound fork exploits |
| Bad debt accumulation | Positions become undercollateralized faster than liquidators act | Various bear market incidents |
3.2 AMM / DEX Attacks
| Vector | Description |
|---|---|
| Sandwich attacks | Front-run + back-run user swaps to extract value |
| Just-in-time (JIT) liquidity | Add concentrated liquidity before large swap, remove after |
| LP token price manipulation | Inflate LP token value via pool manipulation |
| Imbalanced pool draining | Exploit rounding in constant-product math on edge cases |
| Skim attacks | Exploit difference between reserves and actual balance |
3.3 Governance Attacks
| Vector | Description |
|---|---|
| Flash loan governance | Borrow tokens, vote, execute in single tx (Beanstalk $181M) |
| Vote buying | Off-chain markets for governance token voting power |
| Timelock bypass | Exploit governance parameter misconfiguration |
| Proposal griefing | Block legitimate proposals via minimum threshold manipulation |
| Delegate manipulation | Accumulate delegated voting power for malicious proposals |
3.4 Yield Aggregator / Vault Attacks
| Vector | Description |
|---|---|
| Deposit/withdraw manipulation | Manipulate share price between deposit and withdrawal |
| Strategy migration exploit | Drain funds during vault strategy transition |
| Reward token manipulation | Inflate reward calculations via flash-deposited liquidity |
| First depositor attack | In empty vaults, first depositor can manipulate share/asset ratio to steal from subsequent depositors |
| Donation attack | Send tokens directly to vault to skew share price calculations |
First Depositor Attack Detail:
1. Vault is empty (0 shares, 0 assets)
2. Attacker deposits 1 wei -> gets 1 share
3. Attacker donates 1M tokens directly to vault (not through deposit)
4. Share price: 1 share = 1M + 1 tokens
5. Victim deposits 999,999 tokens -> gets 0 shares (integer division rounds down)
6. Attacker withdraws 1 share -> gets 1M + 999,999 tokens
Prevention: Virtual shares/assets offset (OpenZeppelin ERC4626 mitigation), minimum deposit requirements, initial dead shares.
3.5 Token-Specific Attacks
| Vector | Description |
|---|---|
| Fee-on-transfer tokens | Contract receives less than amount — accounting mismatch |
| Rebasing tokens | Balance changes without transfer — breaks cached balances |
| ERC-777 hooks | tokensReceived callback enables reentrancy on token transfer |
| Approval race condition | approve() front-run between old and new allowance |
| Deflationary tokens | Burn on transfer breaks amount assumptions |
| Pausable tokens | External admin can freeze token, DoS-ing protocol |
| Upgradeable tokens | Token behavior can change post-deployment |
| Non-standard return values | Some ERC-20s don't return bool (USDT) |
3.6 Liquid Staking Attacks
| Vector | Description |
|---|---|
| Exchange rate manipulation | Manipulate stETH/ETH ratio for profitable arbitrage |
| Withdrawal queue gaming | Front-run large unstaking events |
| Slashing cascades | Validator slashing depegs liquid staking token |
| Oracle lag exploitation | Exploit delay between slashing event and oracle update |
4. Bridge Vulnerabilities
Cross-chain bridges are the highest-value targets in Web3 — comprising the majority of billion-dollar exploits. They aggregate TVL and rely on complex trust assumptions across multiple chains.
4.1 Bridge Attack Taxonomy
| Attack Vector | Description | Example |
|---|---|---|
| Validator/signer compromise | Compromise N-of-M multisig signers | Ronin ($624M) — 5/9 validators compromised |
| Private key theft | Steal bridge operator keys | IoTeX ($4.4M, 2026), Harmony ($100M) |
| Fake deposit proof | Submit forged proof that deposit occurred on source chain | Poly Network ($611M) |
| Message verification bypass | Exploit weak verification of cross-chain messages | Nomad ($190M) — any message was valid |
| Replay attacks | Replay withdrawal proof across chains or after bridge restart | Wormhole ($326M) |
| Smart contract bugs | Exploit vulnerability in bridge contract logic | BNB Bridge ($586M) |
| Consensus-level attacks | Attack the bridge's own consensus mechanism | — |
| Relayer manipulation | Corrupt or front-run relay messages | — |
4.2 Bridge Architecture Risks
Lock-and-Mint Bridges: Lock assets on source chain, mint wrapped on destination. Risk: if bridge contract is compromised, wrapped tokens become unbacked.
Burn-and-Release Bridges: Burn wrapped tokens, release originals. Risk: fake burn proofs release real assets.
Liquidity Network Bridges: Use LP pools on both chains. Risk: pool draining, imbalanced liquidity exploitation.
Light Client Bridges: Verify source chain consensus on destination. Risk: light client implementation bugs, header forgery.
4.3 Bridge Security Requirements
- Multisig with diversity: Multiple independent signers across organizations, geographies, and infrastructure
- Fraud proofs / optimistic verification: Challenge period for cross-chain messages
- Rate limiting: Cap withdrawal amounts per time window
- Monitoring and alerting: Real-time anomaly detection on bridge transactions
- Timelocked governance: Prevent rapid parameter changes
- Proof verification: Cryptographic verification of cross-chain state (Merkle proofs, ZK proofs)
- Circuit breakers: Auto-pause on anomalous withdrawal patterns
- Key rotation and HSM: Hardware security modules for signing keys, regular rotation
- Incident response plan: Pre-authorized pause mechanisms and recovery procedures
5. Wallet Security & Key Management
5.1 Key Types and Hierarchies
| Key Type | Purpose | Risk |
|---|---|---|
| Seed phrase (BIP-39) | Master secret — derives all keys | Total loss if compromised |
| Private key | Signs transactions for single account | Account compromise |
| HD derivation (BIP-32/44) | Hierarchical deterministic key tree | Path exposure reveals key |
| Multisig keys | M-of-N threshold signing | Reduced single-point-of-failure |
| MPC key shares | Distributed key generation, no single party holds full key | Share compromise, threshold attacks |
5.2 Wallet Attack Vectors
| Vector | Description |
|---|---|
| Seed phrase phishing | Fake wallet UI or support requests seed entry |
| Clipboard hijacking | Malware replaces copied address with attacker's |
| Malicious browser extension | Fake MetaMask or wallet extension steals keys |
| Supply chain attack | Compromised wallet software update injects backdoor |
| Blind signing | User signs transaction without understanding content |
| Approval phishing | User grants approve(attacker, type(uint256).max) via deceptive dApp |
| Hardware wallet supply chain | Tampered device pre-loaded with known seed |
| SIM swap | Attacker takes over phone number to bypass 2FA for exchange accounts |
| Social engineering | Targeted attacks against high-value individuals (Step Finance $27.3M — email compromise) |
| Dust attacks | Small transactions from look-alike addresses to trick copy-paste |
5.3 Key Management Best Practices
For Individual Users:
- Hardware wallet (Ledger, Trezor) for significant holdings — verify on device screen
- Never enter seed phrase digitally — metal backup in physical secure location
- Separate hot wallet (small amounts) from cold storage (bulk holdings)
- Verify transaction details on hardware wallet screen before signing
- Revoke unnecessary token approvals regularly (revoke.cash)
- Use address book / allowlisting for frequent destinations
- Enable transaction simulation (Tenderly, Blowfish) before signing
For Protocol Teams / Treasuries:
- Multisig wallets (Safe/Gnosis Safe): 3-of-5 minimum for treasury operations
- Timelock on admin functions: 24-48 hour delay on parameter changes
- Hardware Security Modules (HSMs): For automated signing (validator keys, relayers)
- Key ceremony: Documented, witnessed key generation with verifiable entropy
- Geographic distribution: Signers in different jurisdictions and infrastructure
- Succession planning: Dead man's switch or social recovery for critical keys
- Regular access review: Audit who holds which keys, rotate when team changes
For Smart Contract Deployers:
- Use CREATE2 for deterministic addresses
- Verify deployment parameters via separate channel
- Immediately transfer ownership to multisig post-deployment
- Lock implementation contracts (
_disableInitializers())
5.4 Operational Security (OpSec) for Crypto
- Dedicated device for high-value transactions — no general browsing
- Unique, strong passwords per service — password manager (not cloud-synced for seed storage)
- Email alias per crypto service — compartmentalize identity
- VPN or Tor for privacy-sensitive operations
- Monitor wallet addresses for unexpected approvals or transactions
- Separate identities for public and high-value activities
- Assume every dApp interaction is potentially hostile
6. Auditing Methodology
6.1 Audit Lifecycle
Phase 1: Scoping & Planning
- Define scope (contracts, chains, external dependencies)
- Gather documentation (specs, architecture diagrams, threat model)
- Identify trust assumptions and privileged roles
- Review prior audits and known issues
Phase 2: Automated Analysis
- Static analysis: Slither (fast, low false positives)
- Symbolic execution: Mythril (path exploration, SWC detection)
- Formal verification: Certora Prover (property-based verification)
- Fuzzing: Echidna / Foundry fuzz (property-based testing)
- Dependency analysis: Check for known vulnerable dependencies
Phase 3: Manual Review
- Line-by-line code review with security focus
- Business logic validation against specification
- Access control mapping: who can call what
- State machine analysis: valid state transitions
- External interaction analysis: all cross-contract calls
- Economic attack modeling: game theory, incentive analysis
- Edge case analysis: zero values, max values, empty arrays, reentrancy points
Phase 4: Exploitation & Verification
- Write PoC exploits for identified vulnerabilities
- Verify findings are reproducible
- Assess exploitability (cost, complexity, prerequisites)
- Test mitigations
Phase 5: Reporting
- Finding severity classification (Critical/High/Medium/Low/Informational)
- Clear reproduction steps
- Specific remediation recommendations
- Executive summary for non-technical stakeholders
Phase 6: Remediation Review
- Verify fixes address root cause (not just symptom)
- Check for regression — fix doesn't introduce new issues
- Re-run automated tools on fixed code
6.2 Manual Review Checklist
Access Control:
- All external/public functions have appropriate access control
- Initialization can only occur once
- Owner/admin cannot rug (or timelock is enforced)
- Role separation between admin operations
- Two-step ownership transfer
Reentrancy:
- CEI pattern followed for all external calls
-
nonReentranton state-changing functions with external calls - Cross-function reentrancy considered (shared state)
- Read-only reentrancy considered (view functions returning stale state)
- ERC-777 hooks considered for token interactions
Arithmetic:
- Solidity >= 0.8.0 or SafeMath used
- All
uncheckedblocks justified and safe - Division before multiplication avoided
- Rounding direction correct (round against user in protocol's favor)
- Precision loss acceptable for use case
External Interactions:
- Return values checked on all low-level calls
-
SafeERC20used for token operations - Fee-on-transfer tokens handled
- Rebasing tokens handled
- Non-standard ERC-20 tokens handled (no bool return, etc.)
Oracle & Price Feeds:
- Oracle freshness validated (stale price rejection)
- Oracle manipulation resistance (TWAP, multiple sources)
- Fallback oracle configured
- Price bounds / sanity checks implemented
Upgradeability:
- Storage layout preserved across upgrades
- Initializer guards present
- Implementation contract locked
- Upgrade authorization properly restricted
- Storage gaps in base contracts
Economic / DeFi Logic:
- Flash loan resistance
- First depositor attack mitigated (for vaults)
- Sandwich attack impact acceptable
- Liquidation mechanism sound
- Fee calculation correct
- Slippage protection present
6.3 Severity Classification
| Severity | Criteria |
|---|---|
| Critical | Direct loss of funds, contract takeover, permanent DoS of critical functions. Exploitable with minimal cost/prerequisites. |
| High | Significant fund loss or protocol disruption under specific conditions. Requires some setup but realistic. |
| Medium | Limited fund loss, temporary DoS, or governance manipulation. Requires significant setup or unlikely conditions. |
| Low | Minor issues, best practice violations, gas optimizations with security implications. No direct fund risk. |
| Informational | Code quality, style, documentation gaps. No security impact. |
7. Tooling Reference
7.1 Static Analysis
| Tool | Type | Strengths | Limitations |
|---|---|---|---|
| Slither | Static analyzer | Fast (<1s), 100+ detectors, low FP, CI-ready | Can't find logic bugs or economic exploits |
| Solhint | Linter | Style + security rules, configurable | Surface-level only |
| Semgrep | Pattern matching | Custom rules for Solidity patterns | Requires rule authoring |
Slither Key Commands:
slither . # Analyze entire project
slither . --print human-summary # Contract overview
slither . --print contract-summary # Function-level summary
slither . --checklist # Markdown audit checklist
slither . --detect reentrancy-eth # Single detector
slither . --exclude-informational # Filter noise
7.2 Dynamic / Symbolic Analysis
| Tool | Type | Strengths | Limitations |
|---|---|---|---|
| Mythril | Symbolic execution | Deep path exploration, SWC detection, bytecode analysis | Slow on large contracts, path explosion |
| Manticore | Symbolic execution | Custom property verification, EVM + native binary | Maintenance mode, steep learning curve |
| Echidna | Property-based fuzzer | Fast, Haskell-powered, CI integration | Requires property specification |
| Foundry Fuzz | Fuzzer + test framework | Integrated with Forge, fast, good DX | Requires property specification |
Mythril Usage:
myth analyze contract.sol # Analyze source
myth analyze -a 0x<address> --rpc <rpc_url> # Analyze deployed
myth analyze contract.sol -t 5 # 5 transaction depth
myth analyze contract.sol --execution-timeout 300 # 5 min timeout
7.3 Formal Verification
| Tool | Type | Strengths |
|---|---|---|
| Certora Prover | Formal verification | Mathematical guarantees, CVL specification language |
| Halmos | Symbolic testing | Foundry-compatible, symbolic execution of Forge tests |
| KEVM | K Framework | Full EVM semantics in K — rigorous but complex |
7.4 Monitoring & Runtime
| Tool | Purpose |
|---|---|
| Forta | Real-time threat detection network with detection bots |
| OpenZeppelin Defender | Contract monitoring, automated incident response |
| Tenderly | Transaction simulation, debugging, alerting |
| Blocknative | Mempool monitoring, front-running detection |
7.5 Recommended Audit Pipeline
1. Slither → Fast first pass, catch low-hanging vulnerabilities
2. Mythril → Symbolic exploration for deeper bugs
3. Echidna/Foundry → Fuzz invariants and properties
4. Manual review → Business logic, economic attacks, access control
5. Certora (optional)→ Formal verification of critical invariants
6. PoC writing → Confirm exploitability of findings
8. SWC Registry Reference
The Smart Contract Weakness Classification (SWC) registry provides a standardized taxonomy. Key entries:
| SWC | Title | Severity | Notes |
|---|---|---|---|
| SWC-100 | Function Default Visibility | Medium | Always set explicit visibility |
| SWC-101 | Integer Overflow/Underflow | High | Mitigated in Solidity >= 0.8.0 |
| SWC-102 | Outdated Compiler Version | Low | Use latest stable compiler |
| SWC-103 | Floating Pragma | Low | Pin pragma to specific version |
| SWC-104 | Unchecked Call Return Value | Medium | Always check return values |
| SWC-105 | Unprotected Ether Withdrawal | Critical | Access control required |
| SWC-106 | Unprotected SELFDESTRUCT | Critical | Access control + consider removal |
| SWC-107 | Reentrancy | Critical | CEI pattern + reentrancy guard |
| SWC-108 | State Variable Default Visibility | Medium | Explicit visibility |
| SWC-109 | Uninitialized Storage Pointer | High | Always initialize, specify data location |
| SWC-110 | Assert Violation | Medium | Use require for input validation |
| SWC-111 | Deprecated Solidity Functions | Low | Replace with current equivalents |
| SWC-112 | Delegatecall to Untrusted Callee | Critical | Only delegatecall trusted contracts |
| SWC-113 | DoS with Failed Call | High | Pull pattern, handle failures |
| SWC-114 | Transaction Order Dependence | High | Commit-reveal, private mempools |
| SWC-115 | Authorization through tx.origin | High | Use msg.sender exclusively |
| SWC-116 | Block Values as Time Proxy | Medium | Tolerance buffers, block numbers |
| SWC-117 | Signature Malleability | High | Use OZ ECDSA library |
| SWC-118 | Incorrect Constructor Name | Critical | Use constructor() keyword |
| SWC-119 | Shadowing State Variables | Medium | Linter detection |
| SWC-120 | Weak Randomness | High | Chainlink VRF |
| SWC-121 | Missing Signature Replay Protection | High | Include nonce + chainId |
| SWC-122 | Lack of Proper Signature Verification | High | Check ecrecover != address(0) |
| SWC-123 | Requirement Violation | Medium | Proper require conditions |
| SWC-124 | Write to Arbitrary Storage | Critical | Validate array bounds |
| SWC-125 | Incorrect Inheritance Order | Medium | C3 linearization awareness |
| SWC-126 | Insufficient Gas Griefing | Medium | Forward sufficient gas |
| SWC-127 | Arbitrary Jump | High | Avoid function type variables |
| SWC-128 | DoS With Block Gas Limit | High | Bound iterations |
| SWC-129 | Typographical Error | Low | Linter + review |
| SWC-130 | Right-To-Left Override (U+202E) | High | Code review, CI checks |
| SWC-131 | Unused Variables | Info | Clean code |
| SWC-132 | Unexpected Ether Balance | Medium | Don't rely on address.balance |
| SWC-133 | Hash Collision (abi.encodePacked) | Medium | Use abi.encode for variable-length |
| SWC-134 | Hardcoded Gas Amount | Low | Avoid hardcoded gas stipends |
| SWC-135 | Code With No Effects | Low | Dead code removal |
| SWC-136 | Unencrypted Private Data On-Chain | High | All on-chain data is public |
Note: SWC registry has not been updated since 2020. Newer vulnerability classes (flash loans, MEV, read-only reentrancy, cross-chain attacks) are not covered. Supplement with EEA EthTrust Security Levels and SCSVS.
9. Historical Exploit Database
9.1 Top Exploits by Loss (All-Time)
| Rank | Protocol | Amount | Date | Attack Type |
|---|---|---|---|---|
| 1 | ByBit | $1.44B | 2025-02-21 | Multisig compromise (Lazarus Group) |
| 2 | Ronin Network | $624M | 2022-03-23 | Bridge validator compromise (5/9 keys) |
| 3 | Poly Network | $611M | 2021-08-10 | Cross-chain bridge message forgery |
| 4 | BNB Bridge | $586M | 2022-10-06 | Bridge contract exploit |
| 5 | Wormhole | $326M | 2022-02-02 | Bridge signature verification bypass |
| 6 | Nomad | $190M | 2022-08-01 | Bridge — any message accepted as valid |
| 7 | BitMart | $196M | 2021-12-04 | Hot wallet key compromise |
| 8 | Beanstalk | $181M | 2022-04-17 | Flash loan governance attack |
| 9 | Compound | $147M | — | Configuration / governance error |
| 10 | Balancer | $128M | — | Oracle manipulation |
| 11 | Mango Markets | $114M | 2022-10-11 | Oracle manipulation (perp price) |
| 12 | Badger DAO | $120M | 2021-12-02 | Front-end compromise (Cloudflare key) |
| 13 | Harmony | $100M | 2022-06-23 | Bridge multisig compromise (2/5 keys) |
| 14 | Curve/Vyper | $69.3M | 2023-07-30 | Compiler bug (Vyper reentrancy lock) |
9.2 Attack Type Distribution (Major Exploits)
| Attack Type | % of Total Loss | Count |
|---|---|---|
| Bridge exploits | ~45% | Ronin, Poly, BNB, Wormhole, Nomad, Harmony |
| Key compromise | ~25% | ByBit, BitMart, Badger, various |
| Smart contract bugs | ~15% | Curve, Cream, various reentrancy |
| Flash loan + oracle | ~10% | Beanstalk, Mango, Yieldblox |
| Configuration errors | ~5% | Compound, Aave |
9.3 Key Lessons
-
Bridges are the #1 target: Aggregate value + complex trust assumptions = maximum attack surface. Four of the top six exploits are bridge attacks.
-
Key management is existential: ByBit ($1.44B) and Ronin ($624M) were not smart contract bugs — they were key/signer compromises. Multisig is necessary but not sufficient; threshold, signer diversity, and operational security matter.
-
Audits are necessary but insufficient: Step Finance ($27.3M, 2026) had audits, bug bounties, and security reviews — compromised via executive email. Security is holistic.
-
Flash loans democratize attacks: Zero-capital attacks via flash loans enable anyone to execute complex financial exploits. Oracle manipulation and governance attacks are the primary use cases.
-
Compiler bugs are real: Curve/Vyper ($69.3M) — a bug in the Vyper compiler's reentrancy lock implementation bypassed the guard. Compiler and toolchain security is part of the threat model.
-
Detection gaps persist: Ronin breach went undetected for 6 days. Real-time monitoring and anomaly detection are critical but widely underdeployed.
-
Human factors dominate: Social engineering, email compromise, insider threats, and operational mistakes account for more loss than pure smart contract bugs.
Appendix A: MITRE ATT&CK Mapping for Web3
| ATT&CK Technique | Web3 Application |
|---|---|
| T1190 — Exploit Public-Facing Application | Smart contract vulnerability exploitation |
| T1195 — Supply Chain Compromise | Malicious npm packages, compromised wallet software |
| T1566 — Phishing | Seed phrase phishing, approval phishing, fake dApps |
| T1078 — Valid Accounts | Compromised private keys, stolen credentials |
| T1059 — Command and Scripting | Malicious transaction construction |
| T1565 — Data Manipulation | Oracle manipulation, state corruption |
| T1499 — Endpoint Denial of Service | Contract DoS, gas griefing |
| T1040 — Network Sniffing | Mempool monitoring for front-running |
| T1557 — Adversary-in-the-Middle | Transaction interception, DNS hijacking of dApp |
| T1530 — Data from Cloud Storage | Exposed private keys in cloud infrastructure |
| T1552 — Unsecured Credentials | Private keys in source code, env vars, logs |
Appendix B: Quick Reference — Solidity Security Checklist
BEFORE DEPLOYMENT:
[ ] Solidity >= 0.8.x with pinned pragma
[ ] All functions have explicit visibility
[ ] Access control on all privileged functions
[ ] CEI pattern on all external calls
[ ] ReentrancyGuard on state-changing external interactions
[ ] SafeERC20 for all token operations
[ ] Oracle freshness and manipulation checks
[ ] Flash loan resistance verified
[ ] Integer math reviewed (unchecked blocks justified)
[ ] Upgrade safety (storage layout, initializer guards)
[ ] Event emissions for all state changes
[ ] Slither clean (no high/medium findings)
[ ] Mythril analysis complete
[ ] Fuzz testing with Echidna or Foundry (>100k runs)
[ ] External audit by reputable firm
[ ] Bug bounty program launched (Immunefi)
[ ] Monitoring and alerting configured (Forta, Defender)
[ ] Incident response plan documented
[ ] Emergency pause mechanism tested
[ ] Timelock on admin functions (24h+ delay)
[ ] Multisig for ownership (3/5 minimum)
Sources: sigp/solidity-security-blog, crytic/not-so-smart-contracts, crytic/slither, ConsenSys/mythril, trailofbits/manticore, swcregistry.io, pcaversaccio/reentrancy-attacks, harendra-shakya/smart-contract-attack-vectors, rekt.news leaderboard, AmazingAng/WTF-Solidity, OWASP Blockchain Security Cheat Sheet