Reproduced Exploit
Beraji KO: nested updateReward makes a full claim pay 0 instead of 1600
fullyClaimReward loops every lock and every reward and calls _claimReward. _claimReward is also marked updateReward, and that modifier loops every lock and every reward again. With 4 and 4 that is 16 outer calls, each walking 16 cells. A 250000 gas stipend reverts the nested claim. paid stays 0. Th…
Chain
Other
Category
dos
Date
Mar 2025
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: 49514-h-02-users-might-not-be-able-to-fully-claim-shieldify-none-b. Standalone Foundry PoC and full write-up: 49514-h-02-users-might-not-be-able-to-fully-claim-shieldify-none-b_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/dos/gas-limit · vuln/logic/reward-calculation
Key info#
| Protocol | Beraji KO |
| Finding | Shieldify H-02, AuditVault 49514 |
| Vulnerable code | StakingKo._claimReward modifier updateReward |
| Harm | Four locks and four rewards owe 1600. The nested claim cannot finish in 250000 gas, so the user is paid 0 and 1600 stays. The control pays 1600 in the same budget |
| Chain | local synthetic |
TL;DR#
fullyClaimReward loops every lock and every reward and calls _claimReward. _claimReward is also marked updateReward, and that modifier loops every lock and every reward again. With 4 and 4 that is 16 outer calls, each walking 16 cells. A 250000 gas stipend reverts the nested claim. paid stays 0. The fair total is 1600, and that 1600 stays in the contract. The same stipend on a claim without the modifier pays 1600.
The vulnerable code#
modifier updateReward() {
uint256 n = COUNT;
for (uint256 i; i < n; i++) {
for (uint256 j; j < n; j++) {
// @> VULN: updateReward walks every lock and reward again inside each _claimReward
scratch = uint256(keccak256(abi.encode(scratch, i, j)));
}
}
_;
}
function _claimReward(uint256 lockId, uint256 rewardId) internal updateReward {
The fix removes updateReward from _claimReward. fullyClaimReward already walks the cells.
Root cause#
The modifier and the outer loop cover the same set. Every cell of the full claim pays for a full pass over the set. Gas grows with the square of locks times rewards, which is the report's 50 by 50 shape. This reduction uses 4 by 4 so the gap fits in one call: the nested claim needs about 328000 gas and the flat claim about 192000.
Preconditions#
COUNT is 4. Each cell owes 100. The reward contract holds 1600. The claim is forwarded with a 250000 gas stipend. run() does not warp.
Attack walkthrough#
- Mint 1600 into the nested staking contract and 1600 into the control.
- Call
fullyClaimRewardwith 250000 gas. The nestedupdateRewarddoes not finish. The call reverts. Paid is 0. The 1600 is still there. - Call the control
fullyClaimRewardwith the same 250000 gas. It pays 1600.
Diagrams#
Impact#
The user is paid 0. The fair claim is 1600. The unpaid rewards stay in the staking contract. The control pays the user 1600.
How to reproduce#
cd 49514-h-02-users-might-not-be-able-to-fully-claim-shieldify-none-b_exp
forge test -vv
run() does not warp. The nested claim pays 0. The control pays 1600.
Sources#
- AuditVault finding: https://github.com/Auditware/AuditVault/blob/main/findings/49514-h-02-users-might-not-be-able-to-fully-claim-shieldify-none-b.md
- Shieldify Beraji-KO review: https://github.com/shieldify-security/audits-portfolio-md/blob/main/Beraji-KO-Security-Review.md
- Reviewed tree: https://github.com/Beraji-Labs/staking-ko/blob/290103f27365cc419fe0a934feaf5f18e6e12d3a/contracts/StakingKo.sol
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 49514-h-02-users-might-not-be-able-to-fully-claim-shieldify-none-b_exp (evm-hack-registry mirror).
- AuditVault finding: 49514-h-02-users-might-not-be-able-to-fully-claim-shieldify-none-b.
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.