All vulnerabilities
CRITICALWeb3exploited in the wild

WEB3-COMPOUND-2021

Web3 · Ethereum · Compound

Summary

On 29 September 2021 Compound executed governance Proposal 062, which upgraded the Comptroller to split COMP reward distribution into separate supply-side and borrow-side speeds, and the upgrade introduced an accounting bug that left roughly $80–150 million in COMP erroneously claimable. In distributeSupplierComp, the guard meant to seed a new supplier's index used the wrong comparison operator: it read if (supplierIndex == 0 && supplyIndex > compInitialIndex) instead of >=. For markets where a user supplied while supplyIndex still equaled compInitialIndex (1e36, e.g. unmigrated markets), the branch failed to fire, so supplierIndex stayed 0 while the global index was 1e36, producing a deltaIndex of 1e36 and crediting that supplier with COMP as if the entire index had accrued to them. The unprotected drip() function could be called repeatedly to push the over-accrued COMP into the Comptroller for claiming. Proposal 064 (executed around 9 October 2021) patched the logic.

How to avoid it in your code

  • Use >= rather than > when a boundary value (e.g. an index equal to its seed) must be treated as already initialized
  • Initialize per-user accumulator indices to the current global index on first interaction, never to zero against a non-zero base
  • Add invariant tests asserting a fresh participant's accrued rewards are zero, including the exact-boundary equal-index case
  • Require multi-party review and formal verification for any change to reward-accounting math before a governance upgrade ships
  • Cap or rate-limit reward payouts per address per block so an accounting error cannot be drained via a public drip()

References

Related vulnerabilities

All Web3 →