Reproduced Exploit

ZeroLend — Incorrect reward distribution when t == roundedTimestamp

1. At an exact epoch boundary, t == roundedTimestamp. 2. The loop uses > so it still writes veSupply[t] from the current locker point. 3. Bob locks more after the checkpoint — real supply rises, week supply stays stale. 4. claim = totalReward * balance / veSupply overpays Bob 4x the honest share.

Jan 2024Otheruntagged2 min read

Chain

Other

Category

untagged

Date

Jan 2024

Source

AuditVault

EVM Playground

Source-level debugger — step opcodes and Solidity in sync

evm-hack-analyzer

The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.

Loading fork state…

Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 40820-incorrect-reward-distribution-when-t-roundedtimestamp-in-fee. Standalone Foundry PoC and full write-up: 40820-incorrect-reward-distribution-when-t-roundedtimestamp-in-fee_exp in the evm-hack-registry mirror.


Vulnerability classes: reward-calculation · reward-theft · reward-accounting

Reproduction: self-contained Foundry PoC with only forge-std — no fork. output.txt · test/40820-…sol.

AuditVault taxonomy: lang/solidity · platform/cantina · severity/high · sector/token · genome: reward-calculation · variant · reward-theft · reward-accounting


Key info#

ImpactHIGH — late lockers overpaid (e.g. 3 instead of 0.75 of epoch rewards) via stale veSupply
ProtocolZeroLend — FeeDistributor._checkpointTotalSupply
Vulnerable codeif (t > roundedTimestamp) break; (should be >=)
Bug classEpoch-boundary off-by-one in week supply checkpoint
FindingCantina — ZeroLend, Jan 2024 · #40820 · reporter 0xarno
Reportcantina_competition_zerolend_jan2024.pdf
SourceAuditVault
FixBreak on t >= roundedTimestamp (do not write incomplete week)
Compiler^0.8.24 (PoC)

TL;DR#

  1. At an exact epoch boundary, t == roundedTimestamp.
  2. The loop uses > so it still writes veSupply[t] from the current locker point.
  3. Bob locks more after the checkpoint — real supply rises, week supply stays stale.
  4. claim = totalReward * balance / veSupply overpays Bob 4x the honest share.

Diagrams#

flowchart TD A["Alice locks 100"] --> B["checkpoint at epoch boundary"] B --> C["veSupply week = 100 written"] C --> D["Bob locks 300 supply=400"] D --> E["Bob claim uses supply 100"] E --> F["Bob gets 3x reward vs honest 0.75"]

Impact#

Week-bound total-supply invariance breaks; reward accounting skews toward users who lock after a boundary checkpoint.

Sources#


Sources & further analysis#

Reproductions & code

Alerts & third-party analyses

  • Web3Sec X hacked database: search.
  • Rekt leaderboard: search.
  • Solodit incident search: search.

These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.