web3.path

PHASE 21 adversarial review · 16–24 hours

Smart Contract Security Engineering

Security work is a disciplined attempt to falsify the system’s claims. Tools prioritize attention; they do not establish correctness.

Goal — take one small protocol from written invariants through adversarial tests, static analysis, review evidence, and an incident-ready release decision.

1. Start with a threat model

Before reading code, make four tables: assets (what can be lost), authorities (who can change what), trust boundaries (untrusted contracts/oracles/relayers), and invariants (facts that must remain true). State the attacker’s capabilities: arbitrary calldata, flash liquidity, transaction ordering, malicious token callbacks, stale dependencies, and compromised low-privilege keys.

ClaimConcrete invariantTest strategy
Users cannot withdraw others’ fundswithdrawn[user] ≤ credited[user]handler invariant + impersonated callers
Shares cannot create assetsredeemable shares ≤ accounted assetsfuzz deposits, donations, losses, rounding edges
Admin cannot silently drain fundsadmin functions are bounded or timelockedrole/time-delay/revert tests + event assertions
Messages execute oncemessageId transitions pending → consumed exactly onceduplicate/reordered delivery tests

2. Reentrancy is an interaction problem

function withdraw(uint256 shares, address receiver) external nonReentrant {
    uint256 assets = previewRedeem(shares);
    _burn(msg.sender, shares);                 // effects first
    SafeERC20.safeTransfer(asset, receiver, assets); // interaction last
    emit Withdraw(msg.sender, receiver, assets, shares);
}

Audit every external boundary: ETH transfers, ERC-777 hooks, ERC-721/1155 receiver callbacks, token adapters, routers, oracles, and delegatecalls. Test cross-function and read-only reentrancy, not only recursive calls into the same method. Use a hostile receiver/token mock that calls every public method during the callback.

3. Signatures, permissions, and governance

4. Economic and integration attacks

ClassAdversarial test
Oracle manipulationMove spot price; use stale/zero/negative feeds; cross the circuit-breaker boundary.
MEV / sandwichExecute user trade after an adverse reserve move; prove minOut/deadline rejects it.
Token incompatibilityUse no-return, fee-on-transfer, rebasing, paused/blacklisted and callback tokens.
Precision / roundingFuzz 0/1/max values, decimal mismatches, donation and first-depositor paths.
DoS / griefingFill queues, revert callbacks, grow user arrays, and make a receiver fail.

5. Review pipeline

forge fmt --check
forge test -vvv
forge test --match-path "test/invariant/*" --fuzz-runs 20000
forge snapshot --check
slither . --exclude-dependencies
# Add your project-specific static/formal tools only after tests are reliable.

Triage findings in a log: identifier, severity, exploit preconditions, affected invariant, fix, regression test, reviewer, and disposition. “Slither clean” and “90% coverage” are not a security conclusion.

5b. Echidna & mutation testing

# echidna.yaml — fuzz invariants on hardened contracts
testMode: assertion
testLimit: 50000
contracts:
  - HardenedVault

5c. Responsible disclosure

Before testnet launch, add SECURITY.md (template: labs/SECURITY.md): scope, contact, safe harbor, embargo policy. Practice with a mock audit in §6 — findings must include exploit path and remediation proof.

6. Practical lab — exploit then harden

Deliverable
  1. Write a deliberately vulnerable vault: external transfer before accounting, raw ERC-20 call, owner-only upgrade, and unsigned/under-specified withdrawal authorization.
  2. Create attacker contracts/tests for reentrancy, non-standard tokens, replay, role escalation, donation inflation, and price manipulation. Demonstrate the loss or invariant failure.
  3. Harden the vault. Every fix must retain its exploit test as a passing regression test.
  4. Produce a two-page threat model, authority diagram, invariant list, Slither triage, and Safe/timelock deployment plan.
  5. Run a mock audit: review a peer’s diff, submit findings with exploit path and proof, then verify the remediation.

Lab repo: labs/phase-21-security/ — starter breaks VulnerableVault; solution ships HardenedVault + CI.

← Phase 20Phase 22: DeFi Protocol Engineering →