# New staking between reward epochs will dilute rewards for existing stakers. Anyone can then front-run `OperationalStaking.rewardValidators()` to steal rewards

OperationalStaking.rewardValidators counts stakes made mid-epoch, letting an attacker front-run distribution with a large stake to siphon a share of rewards.

- Payout: Contest reward
- Severity: medium
- Program: Covalent
- Credited: Atharv
- Disclosed: 2023-11-10
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-11-covalent-judging/issues/47
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-11-covalent%3AM-3
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:reward-distribution

**Target:** OperationalStaking.sol rewardValidators() staking/reward accounting
**Root cause:** rewardValidators() distributes rewards proportional to current total stake, including stakes added after the epoch's work was performed; no checkpoint/pending-stake accounting separates new stakes from epoch-eligible ones.
**Steps:**
1. Validator Alice has 50000 CQT total stake (self + delegators).
2. Staking manager calls `rewardValidators()` to distribute 1000 CQT proportional to stake.
3. Attacker Bob observes the pending `rewardValidators()` tx in mempool and front-runs with a 50000 CQT stake into Alice.
4. Alice's total becomes 100000; Bob owns half and receives ~half the 1000 CQT reward.
5. Bob unstakes and re-stakes via `recoverUnstaking()` to repeat the attack each epoch.
**How found:** Code review of rewardValidators() reward math: noticed it uses current total stake without distinguishing stakes added after the epoch's work, then reasoned about mempool front-running of the distribution call.
**Exploitation:** Attacker watches the mempool for the staking manager's rewardValidators() call, submits a large stake tx with higher gas to land before it, captures a proportional share of the epoch reward despite staking for seconds, then exits and re-enters via recoverUnstaking() to repeat.
**Escalation:** Repeatable each reward epoch by cycling stake through recoverUnstaking(); scales with stake size relative to validator pool.
**Insight:** When reward distribution reads live stake balances rather than epoch-snapshotted/checkpointed weights, any permissionless stake/unstake path becomes a front-run vector against the distribution tx; check whether new deposits are excluded until the next epoch.
