# ValidatorRegistry::validatorScore/getPastValidatorScore allows validator to earn full rewards without actually engaging with the protocol

New validators in Virtuals ValidatorRegistry get base score equal to total proposals, granting 100% reward uptime without ever voting.

- Payout: Contest reward
- Severity: high
- Program: Virtuals Protocol
- Credited: oakcobalt
- Disclosed: 2025-08-04
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2025-04-virtuals-protocol#h-05
- Library page: https://bugbountylibrary.com/r/c4%3A2025-04-virtuals-protocol%3AH-05
- 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:** ValidatorRegistry / AgentRewardV2 reward accounting contracts
**Root cause:** _initValidatorScore sets _baseValidatorScore to _getMaxScore(virtualId) = totalProposals(virtualId), so a freshly added validator starts with a score equal to all historical proposals despite zero participation.
**Steps:**
1. Create 2 proposals; have validator1 vote on only the first (score=1, 50% uptime).
2. Mint tokens to validator2 and call `agentNft.addValidator(1, validator2.address)`.
3. Read `agentNft.validatorScore(1, validator2.address)` -> returns 2 (base score = totalProposals).
4. Compute uptime: validator2 = 2/2 = 100% despite no votes; validator1 = 1/2 = 50%.
5. Rewards in AgentRewardV2 use `(validatorRewards * validatorScore) / totalProposals`, so validator2 receives full rewards.
**How found:** Code review of _initValidatorScore noticing base score is seeded from totalProposals rather than zero, then reasoning that validatorScore adds base + participation, so a new validator instantly matches max score.
**Exploitation:** A staker delegates to a freshly registered validator each epoch; the new validator's base score equals totalProposals, yielding 100% reward allocation without casting any votes, diluting honest validators' payouts.
**Insight:** When a scoring system adds a 'base' term to a participation term and normalizes by total historical count, check whether the base is seeded from that same total — a fresh entrant then trivially hits 100% and dilutes incumbents.
