T09 · Insecure Skill Coding Practices
Error
- Location
- contracts/artifacts/build-info/a5d75f9256251cc8c46c7f853791cdf4.json:1
- Finding
- Repeated harvest calls can drain deposited vault assets<![CDATA[ ## Vulnerability Details **File Location**: `contracts/artifacts/build-info/a5d75f9256251cc8c46c7f853791cdf4.json:1` **Vulnerability Type**: Broken reward accounting **Risk Level**: Critical ### Vulnerable Code ```solidity function harvest() external whenNotPaused returns (uint256 yieldAmount) { require(shareBalance[msg.sender] > 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
- <![CDATA[ ## Remediation Suggestions - Track reward debt and the last accrual checkpoint for every user. - Calculate rewards only over elapsed time and settle the checkpoint before transferring tokens. - Fund payouts only from realized protocol profits or a separately accounted reward reserve. - Reduce the appropriate reward liability when rewards are harvested. - Verify that actual token balances cover all user principal and reward liabilities. - Apply checks-effects-interactions and reentrancy protection. - Add tests proving that an immediate second harvest cannot claim the same reward and that one user's harvest cannot consume another user's principal. ]]>
