# When the unlockOverride flag is true, users can "freely" vote for gauge weights.

With unlockOverride enabled, users lock CANTO, vote gauge weights, then immediately withdraw, boosting gauge weight for free.

- Payout: Contest reward
- Severity: medium
- Program: Canto
- Credited: said
- Disclosed: 2024-04-26
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-03-neobase-findings/issues/5
- Library page: https://bugbountylibrary.com/r/c4%3A2024-03-neobase%3AM-07
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:governance

**Target:** VotingEscrow.sol / GaugeController.sol
**Root cause:** When unlockOverride is true, withdraw() bypasses the lock expiry check, but createLock and increaseAmount remain unrestricted, so a user can lock, vote, and withdraw in the same epoch.
**Steps:**
1. gov calls `toggleUnlockOverride()` to set unlockOverride=true
2. user calls `ve.createLock{value: 1 ether}(1 ether)`
3. user calls `gc.vote_for_gauge_weights(gauge1, 10000)` to direct 100% weight
4. user calls `ve.withdraw()` immediately, recovering the CANTO
5. gauge_relative_weight_write for next epoch reflects the boosted weight
**How found:** Reading withdraw() logic, noticed unlockOverride bypasses the lock-expiry require, then checked that createLock/increaseAmount had no corresponding guard, enabling lock-vote-withdraw in one transaction window.
**Exploitation:** Lock tokens, cast gauge vote to inflate desired gauge's relative weight, then withdraw the same tokens immediately since unlockOverride skips the expiry check, leaving the vote weight in place for free.
**Insight:** When a governance override relaxes one side of a lock (withdraw), audit the symmetric entry paths (createLock/increaseAmount) for missing guards that let the same capital be reused within a single epoch.
