# Anyone can vote multiple times by using multiple addresses and transferring a voting token if private mode is off

Voting power snapshotted from DToken balance without moving with transfers, letting a holder double-count votes by transferring tokens between addresses.

- Payout: Contest reward
- Severity: high
- Program: Goat
- Credited: Stiglitz
- Disclosed: 2024-06-12
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_goat_mar2024.pdf#3.1.1
- Library page: https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.1
- Tags: domain:web3 impact:integrity kind:contest platform:cantina sev:high tech:solidity technique:source-review vuln:business-logic vuln:governance

**Target:** Voting.sol / DToken voting power accounting
**Root cause:** Voting::updatePower reads the caller's current DToken balance as voting power, but DToken::_beforeTokenTransfer only notifies distributors and never moves voting power with the transferred amount.
**Steps:**
1. Ensure DToken is not in private mode so transfers are allowed.
2. User A holding X DToken calls `Voting::updatePower`, recording power X.
3. User A transfers X DToken to User B.
4. User B calls `Voting::updatePower`, recording power X again.
5. Repeat across n addresses to multiply voting power n times.
**How found:** Noticed DToken inherits PERC private mode gating transfers, and that _beforeTokenTransfer only loops distributors without adjusting voting power, so balance-based power can be re-snapshotted after transfer.
**Exploitation:** A token holder registers voting power, transfers the same tokens to a fresh address, registers power again, and repeats to inflate attackerPower/defenderPower in votes.
**Escalation:** Scale by creating n addresses to make voting power n times stronger.
**Insight:** When voting/governance power is derived from a live token balance, check whether the transfer hook moves that power; if only rewards are updated, power can be re-registered per address.
