# Cannot remove delegation from a token to another token

removeDelegation reads the delegator's own checkpoint instead of the delegatee's, so delegation can never be revoked, permanently locking voting power.

- Payout: Contest reward
- Severity: high
- Program: Golom
- Credited: Bahurum
- Disclosed: 2023-04-05
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-07-golom-findings/issues/751
- Library page: https://bugbountylibrary.com/r/c4%3A2022-07-golom%3AH-11
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:governance

**Target:** VoteEscrowDelegation.sol removeDelegation (veGolom NFT delegation)
**Root cause:** removeDelegation loads checkpoints[tokenId] (the delegator's own list of delegators) instead of the delegatee's checkpoint, so removeElement never finds tokenId and the delegation persists.
**Steps:**
1. Owner of tokenId calls `removeDelegation(tokenId)` after having delegated to another token.
2. Function reads `checkpoints[tokenId][nCheckpoints-1]` — the list of delegators TO tokenId, not the delegatee's list.
3. `removeElement(checkpoint.delegatedTokenIds, tokenId)` finds nothing (unless self-delegation), so delegation remains.
4. Delegatee token keeps the delegator's voting power permanently.
**How found:** Code reading of removeDelegation: noticed the checkpoint indexed by tokenId is the delegators list, not the delegatee's, so removal is a no-op.
**Exploitation:** A delegator cannot revoke; the delegatee retains voting power indefinitely, enabling governance attacks via accumulated unrevocable votes.
**Escalation:** Accumulated locked delegations concentrate voting power in delegatee tokens, enabling governance manipulation.
**Insight:** In delegation bookkeeping, verify which side of the mapping a checkpoint array stores; removal must mutate the delegatee's delegator list, not the delegator's own.
