# Any Malicious Arbitrary Actor Can Cause Temporary or Permanent Lock of Reward Distri- bution

Attacker calls claimRewards with an unregistered program name, setting lastUpdateTimestamp nonzero so immediateDistribution skips program creation, locking rewards permanently.

- Payout: Contest reward
- Severity: medium
- Program: Silo
- Credited: SUPERMAN-I4G
- Disclosed: 2025-03-19
- Write-up quality: 7/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_silo.pdf#3.2.10
- Library page: https://bugbountylibrary.com/r/cantina%3Asilo%3A3.2.10
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:cantina sev:medium tech:solidity technique:race-window technique:source-review vuln:access-control vuln:business-logic vuln:reward-distribution

**Target:** SiloIncentivesController.sol reward distribution contract
**Root cause:** _getOrCreateImmediateDistributionProgram uses lastUpdateTimestamp==0 as the unregistered sentinel, but _updateAssetStateInternal writes lastUpdateTimestamp even when newIndex==oldIndex, and claimRewards accepts arbitrary unregistered program names without validating rewardToken.
**Steps:**
1. Derive program name for target reward token: `Strings.toHexString(_rewardToken)`
2. Attacker calls `claimRewards(attacker, [programName])` — no registration check, _accrueRewardsForPrograms sets lastUpdateTimestamp to block.timestamp
3. Notifier calls `immediateDistribution(_rewardToken, amount)`; _getOrCreateImmediateDistributionProgram sees lastUpdateTimestamp != 0 and skips _createIncentiveProgram
4. Distribution executes against a program with rewardToken==address(0); users' `claimRewards(user1, [programName])` reverts
5. Owner cannot recover: `createIncentivesProgram` reverts TooLongProgramName since hex token address exceeds 32 bytes
**How found:** Code reading of the creation sentinel (lastUpdateTimestamp==0) versus the unconditional timestamp write in _updateAssetStateInternal, plus noticing claimRewards lacks a registration check on supplied program names.
**Exploitation:** Front-run the notifier's immediateDistribution for an unregistered reward token by calling claimRewards with the hex-address program name, forcing the creation check to be bypassed so the distributed amount is stranded with no claimable program and no owner recovery path.
**Insight:** When a contract uses a zero-value field as an 'uninitialized' sentinel, check every code path that writes that field — including no-op accrual branches — for unauthenticated callers who can pre-set it and defeat lazy initialization.
