# ConvexStakingWrapper._calcRewardIntegral() Can Be Manipulated To Steal Tokens From Other Pools

Unguarded getReward plus balance-delta reward accounting lets a sole staker of one Convex pool claim rewards earned by all pools sharing the same token.

- Payout: Audit contest
- Severity: high
- Program: Concur Finance
- Found by: leastwood
- Disclosed: 2022-05-24
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2022-02-concur-findings/issues/146
- Library page: https://bugbountylibrary.com/r/c4%3A2022-02-concur%3AH-11
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:reward-distribution

**Target:** ConvexStakingWrapper.sol reward accounting (_calcRewardIntegral)
**Root cause:** _calcRewardIntegral computes d_reward as the contract's whole token balance minus reward.remaining, so any tokens claimed directly via the unguarded getReward on other pools inflate the delta attributed to the current pool.
**Steps:**
1. Deploy scenario: two convex pools _pid 0 and 1, both distributing cvx.
2. Alice deposits LP into pool 0 as sole staker; pool 1 has several stakers.
3. Both pools accrue 100 cvx each.
4. Alice calls `IRewardStaking(convexPool[0]).getReward` and `IRewardStaking(convexPool[1]).getReward` directly, sending 200 cvx to the wrapper.
5. Alice calls deposit with 0 amount to trigger `_calcRewardIntegral` on pool 0; `d_reward = bal - reward.remaining` = 200.
6. As sole staker of pool 0, Alice is credited the full 200 cvx, siphoning pool 1's rewards.
**How found:** Code review of the modified ConvexStakingWrapper design: noticed multi-pool aggregation plus balance-delta accounting (bal - reward.remaining) combined with an unguarded getReward, hypothesizing that cross-pool claims would be misattributed.
**Exploitation:** Attacker stakes in a pool where they are the sole staker, directly invokes the unguarded getReward on multiple pools sharing the same reward token to inflate the wrapper's balance, then triggers _calcRewardIntegral via a zero-amount deposit to claim the aggregated delta as their own reward.
**Insight:** When a contract tracks rewards by comparing its own token balance to a stored 'remaining' value, any externally callable function that increases that balance (like an unguarded getReward) becomes an inflation primitive; check whether shared reward tokens across pools let one pool's delta absorb another's.
