Reproduced Exploit
Suzaku: Undistributed-rewards sum double-counts a multi-vault curator, stranding reward tokens
Chain
Other
Category
untagged
Date
Jan 1970
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
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.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 61233-incorrect-summation-of-curator-shares-in-claimundistributedr. The historical source/toolchain is unavailable; this entry is documentation only and claims no executable Forge PoC.
Vulnerability classes: vuln/reward-accounting · vuln/double-counting · vuln/stranded-funds
Reproduction: a faithful minimal reproduction of the vulnerable finding — the vulnerable function is reproduced verbatim (marked
@>) with faithful minimal doubles; local deploy, no fork.
Root cause#
totalDistributedShares += curatorShares[epoch][curator] is summed once PER OWNED VAULT, so a curator owning two vaults is counted twice. That inflates totalDistributedShares, shrinking undistributedRewards = totalRewards - mulDiv(totalRewards, totalDistributedShares, 10000), so the distributor claims 30,000 instead of 40,000 — 10,000 tokens are permanently stranded.
// Sum curator shares
for (uint256 i = 0; i < vaults.length; i++) {
address curator = VaultTokenized(vaults[i]).owner();
totalDistributedShares += curatorShares[epoch][curator]; // @> counts each curator once PER OWNED VAULT, inflating the total
}
Why it's exploitable here#
- The share summation iterates vaults, not curators, so a curator owning N vaults contributes N times.
- An inflated
totalDistributedSharesmakesundistributedRewards = totalRewards - mulDiv(totalRewards, totalDistributedShares, 10000)too small. - The under-claimed remainder stays permanently stuck in the Rewards contract.
Attack path#
Marked-line walkthrough (Playground)#
The EVM Playground pins each step to the exact executed source line in Rewards:
- Line 171 — VULN. totalDistributedShares double-counts a curator who owns multiple vaults, inflating the distributed total.
- Line 174 — undistributedRewards = totalRewards - mulDiv(totalRewards, totalDistributedShares, 10000) is understated.
- Line 177 — the distributor receives only 30,000; the remaining 10,000 stays stuck in the Rewards contract.
PoC#
Registry (Foundry, local deploy — exploit path + a fixed-variant control):
cd 61233-incorrect-summation-of-curator-shares-in-claimundistribute_exp
forge test -vv
Expected: both tests PASS — the exploit test sets up a two-vault curator and asserts 10,000 stranded; the fixed summation lets the distributor claim the full 40,000. The browser EVM Playground is served at /hacks/61233-incorrect-summation-of-curator-shares-in-claimundistribute/.
Remediation#
Sum each curator's shares once per curator (dedupe by curator), not once per owned vault.
References#
- AuditVault finding: https://github.com/Auditware/AuditVault/blob/main/findings/61233-incorrect-summation-of-curator-shares-in-claimundistributedr.md
Sources & further analysis#
Reproductions & code
- No executable Forge reproduction is claimed; the historical source/toolchain was unavailable for this finding.
- AuditVault finding: 61233-incorrect-summation-of-curator-shares-in-claimundistributedr.
- Upstream DeFiHackLabs PoC directory: src/test.
Alerts & third-party analyses
- DeFiHackLabs incident explorer: search "Suzaku: Undistributed-rewards sum double-counts a multi-vault curator, stranding reward tokens".
- 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.