# Malicious users can drain immediate rewards via frontrun

Attacker frontruns SiloIncentivesController.immediateDistribution() by depositing large stake, capturing most of the one-second reward emission meant for existing holders.

- Payout: Contest reward
- Severity: medium
- Program: Silo
- Credited: 0x37
- Disclosed: 2025-03-19
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_silo.pdf#3.2.6
- Library page: https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.6
- Tags: domain:web3 impact:funds-loss kind:contest platform:cantina sev:medium tech:evm tech:solidity technique:race-window vuln:business-logic vuln:race-condition vuln:reward-distribution

**Target:** SiloIncentivesController reward distribution contract
**Root cause:** immediateDistribution sets emissionPerSecond to the full amount for a single second and calls _updateAssetStateInternal against current totalStaked, so rewards accrue pro-rata to whatever stake exists at that instant; stake added just before the call captures the emission.
**Steps:**
1. Create incentives program with emissionPerSecond=1e6, distributionEnd=now+1000
2. user1 deposits 100e18 into silo0, accrues normal rewards for 50s
3. user2 deposits 2000e18 into silo0 immediately before distribution
4. hook calls `_controller.immediateDistribution(address(_rewardToken), uint104(7e7))`
5. user2 withdraws 2000e18 and calls `_controller.claimRewards(user2)`, capturing most of the 7e7 emission
6. user1 claims and receives only a small fraction of the immediate distribution
**How found:** Reviewer read immediateDistribution and noticed it snapshots totalStaked at call time with a one-second emission window, making reward share purely a function of instantaneous stake — trivially gameable by ordering transactions around the owner's call.
**Exploitation:** Attacker monitors mempool for the owner's immediateDistribution tx, deposits a large stake in the same block ahead of it, then withdraws and claims after the one-second emission accrues, siphoning rewards from long-term stakers.
**Insight:** Any reward function that sets emissionPerSecond to a lump sum for a single block and updates state against current totalStaked is frontrunnable; check whether stake weight is time-averaged or snapshot-based before the distribution call.
