Reproduced Exploit
Cod3x RewardsDistributor — dust supply overflows the uint104 index and locks the claim
The reward index is emissionPerSecond timeDelta 10decimals / totalBalance. With emission 3e13, one second, 18 decimals, and totalBalance == 1, the index is 3e31. type(uint104).max is about 2.028e31, so the require reverts and the claim never transfers. 1000 DAI funded into that distributor stays th…
Chain
Other
Category
arithmetic
Date
Dec 2024
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: 49176-index-can-reach-typeuint104max-when-asset-totalsupply-is-dus. Standalone Foundry PoC and full write-up: 49176-index-can-reach-typeuint104max-when-asset-totalsupply-is-dus_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/arithmetic/overflow · vuln/dos/frozen-funds
Key info#
| Protocol | Cod3x RewardsDistributor |
| Finding | Spearbit, Saw-mon and Natalie, AuditVault 49176 |
| Vulnerable code | index update require(newIndex <= type(uint104).max) |
| Harm | 1000 DAI stuck. The dust claim reverts. A 1e18 supply pays 3e13. |
| Chain | local synthetic |
TL;DR#
The reward index is emissionPerSecond * timeDelta * 10**decimals / totalBalance. With emission 3e13, one second, 18 decimals, and totalBalance == 1, the index is 3e31. type(uint104).max is about 2.028e31, so the require reverts and the claim never transfers. 1000 DAI funded into that distributor stays there. The same emission against a 1e18 supply advances the index by 3e13 and pays 3e13 to the holder.
The vulnerable code#
return (EMISSION * timeDelta * (10 ** DECIMALS)) / totalBalance + currentIndex;
if (newIndex != oldIndex) {
// @> VULN: dust totalBalance makes newIndex exceed uint104, so this require reverts and the claim never pays
require(newIndex <= type(uint104).max, "Index overflow");
rewardConfigIndex = uint104(newIndex);
}
Distribution end is 1 and the last update is 0, so the elapsed time is one second on both Foundry's timestamp and the playground timestamp.
Root cause#
The index scales rewards by 10**decimals / totalBalance. A dust supply, even for a single second, blows a uint104 index. The overflow check is inside the claim path, so the revert locks the rewards instead of skipping the update.
Preconditions#
totalBalance is 1 while emission and decimals are the values above. The distributor already holds the reward tokens the claim would pay.
Attack walkthrough#
- Preview index on supply 1 is
30000000000000000000000000000000, aboveuint104max20282409603651670423947251286015. - 1000 DAI is transferred into the dust distributor.
claimcallsupdateIndex, the require reverts, and the 1000 DAI is still there.- The control distributor has supply
1e18. Its claim pays30000000000000.
Diagrams#
Impact#
Reward claims and any later action that updates the index revert for as long as the dust supply is what the formula divides by. The 1000 DAI cannot be pulled out through claim. Depositors on a normal supply are unaffected: the control pays.
Remediation#
Skip the index update when normalized supply is below a threshold, or widen the index so this emission cannot hit the cap. Do not put a reverting overflow check on the claim path.
How to reproduce#
cd 49176-index-can-reach-typeuint104max-when-asset-totalsupply-is-dus_exp
forge test -vv
Sources#
- AuditVault finding: https://github.com/Auditware/AuditVault/blob/main/findings/49176-index-can-reach-typeuint104max-when-asset-totalsupply-is-dus.md
- Spearbit report: https://github.com/spearbit/portfolio/blob/master/pdfs/Cod3x-Spearbit-Security-Review-December-2024.pdf
- The finding says Cod3x fixed this in PR 34.
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 49176-index-can-reach-typeuint104max-when-asset-totalsupply-is-dus_exp (evm-hack-registry mirror).
- AuditVault finding: 49176-index-can-reach-typeuint104max-when-asset-totalsupply-is-dus.
Alerts & third-party analyses
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.