# castVote can be called by anyone even those without votes

Governance._castVote lacks a zero-vote check, letting anyone vote from many addresses and claim per-address gas refunds to drain the vault.

- Payout: Contest reward
- Severity: medium
- Program: Frankendao
- Credited: hansfriese
- Disclosed: 2022-10-31
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2022-11-frankendao-judging/issues/25
- Library page: https://bugbountylibrary.com/r/sherlock%3A2022-11-frankendao%3AM-7
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:solidity technique:source-review vuln:business-logic vuln:governance

**Target:** Governance.castVote / _castVote voting flow
**Root cause:** _castVote never reverts when staking.getVotes(_voter) returns 0, so addresses with no voting power can still cast a vote and mark a receipt.
**Steps:**
1. Deploy or control many addresses with zero staking votes.
2. For each address call `castVote(proposalId, support)` while proposal is Active.
3. _castVote records receipt.hasVoted=true and votes=0 without reverting.
4. Each address claims the per-address vote gas refund from the vault.
5. Repeat across many addresses until the refund pool is drained.
**How found:** Code review of _castVote: noticed the only reverts are inactive proposal, invalid support, and already-voted; staking.getVotes never reverts, so zero-vote callers pass through and still earn the per-address refund.
**Exploitation:** Attacker spins up numerous zero-vote addresses, votes on an active proposal from each, and collects the per-address voting refund, siphoning the vault's refund reserve with no personal stake required.
**Insight:** When a payout/refund is keyed per address, check whether the qualifying action enforces a nonzero stake; missing zero-value guards turn sybil addresses into a drain primitive.
