# Attacker can steal 99% of total balance from any reward token in any Staking contract

Any user can attach an existing MultiRewardStaking contract to their own vault and call changeRewardSpeed to set an absurd rewardsPerSecond, draining 99% of reward tokens.

- Payout: Contest reward
- Severity: high
- Program: Popcorn
- Credited: gjaldon
- Disclosed: 2023-09-07
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2023-01-popcorn-findings/issues/263
- Library page: https://bugbountylibrary.com/r/c4%3A2023-01-popcorn%3AH-09
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:accounting-error vuln:business-logic

**Target:** VaultController / MultiRewardStaking reward speed configuration
**Root cause:** VaultController lets any vault creator attach an arbitrary existing Staking contract and call changeStakingRewardsSpeeds on it; MultiRewardStaking.changeRewardSpeed imposes no upper bound on rewardsPerSecond and _calcRewardsEnd miscalculates rewardsEndTimestamp.
**Steps:**
1. Deploy attacker vault via `controller.deployVault(...)` passing the victim's existing `staking` contract as the staking arg.
2. Deposit a small amount into the victim staking contract to have a position.
3. Call `controller.changeStakingRewardsSpeeds([attackerVault], [rewardToken], [990_099_990 ether])` to set an absurd rewardsPerSecond.
4. `vm.warp(block.timestamp + 12)` to accrue rewards.
5. Call `MultiRewardStaking(staking).claimRewards(alice, rewardTokens)` to withdraw ~99% of the reward token balance.
**How found:** Code review of VaultController.deployVault (no restriction on which staking contract a vault may reference) combined with changeStakingRewardsSpeeds authorization (only checks vault creator) and missing bounds in changeRewardSpeed; confirmed with a Foundry PoC.
**Exploitation:** Attacker deploys a vault pointing at the victim's Staking contract, making themselves the vault creator authorized to change reward speeds. They set rewardsPerSecond to a huge value, wait ~12 seconds, and claim rewards, extracting 999,999 of 1,000,000 reward tokens; only dust remains due to rounding.
**Escalation:** Works against any Staking contract on-chain since any vault creator can attach any existing staking contract; attacker tunes stake amount, reward speed, and wait time to maximize drain vs cost.
**Insight:** When a factory lets users attach shared singleton contracts (staking, reward pools) to their own instances, check whether per-instance admin functions then mutate shared state; also audit reward-rate setters for missing upper bounds and end-timestamp math.
