T09 · Insecure Skill Coding Practices
- Location
contracts/artifacts/build-info/a5d75f9256251cc8c46c7f853791cdf4.json:1- Finding
Repeated harvest calls can drain deposited vault assets
- Content
View full analysis
0, "No shares to harvest"); yieldAmount = calculateUserYield(msg.sender); require(yieldAmount > 0, "No yield available"); require( IERC20(underlying).transfer(msg.sender, yieldAmount), "Yield transfer failed" ); accumulatedYield += yieldAmount; return yieldAmount; } function calculateUserYield(address user) public view returns (uint256) { if (shareBalance[user] == 0) { return 0; } uint256 userAssets = calculateAssetsFromShares(shareBalance[user]); return (userAssets * 27) / 100000; } ``` ### Technical Analysis The packaged compiler build information embeds the source of `YieldVault.sol`. Its reward calculation depends only on the caller's current shares. It does not track the caller's previously claimed rewards, reward debt, or elapsed accrual period. Calling `harvest()` transfers tokens to the caller but does not decrease `totalAssets`, clear accrued rewards, or advance a per-user reward checkpoint. Consequently, the same nominal yield remains claimable after every successful call. The transfer is funded from the vault's underlying-token balance, which includes user deposits rather than a separately accounted reward reserve. ### Attack Path 1. The attacker acquires underlying tokens and approves the vault. 2. The attacker deposits enough tokens to receive a positive share balance. 3. The attacker calls `harvest()`. 4. The contract calculates a positive reward from the unchanged share balance. 5. The attacker repeats `harvest()` without waiting for any new yield. 6. Each call transfers additional underlying tokens from the vault. 7. Ca ...[truncated 404 chars]- Remediation
View remediation
