# zerolend.votingpowerof() doesn't check ownershipchange block of the token, makes flash nft protection redundant

ZeroLocker.votingPowerOf omits the ownershipChange same-block check used by balanceOfNFT, letting a flash-loaned NFT vote in the block it was acquired.

- Payout: Contest reward
- Severity: medium
- Program: Zerolend
- Credited: osmanozdemir1
- Disclosed: 2024-09-16
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_zerolend_jan2024.pdf#3.2.11
- Library page: https://bugbountylibrary.com/r/cantina%3Azerolend_jan2024%3A3.2.11
- Tags: domain:web3 impact:integrity kind:contest platform:cantina sev:medium tech:evm tech:solidity technique:incomplete-fix technique:source-review vuln:business-logic vuln:governance

**Target:** ZeroLocker.sol voting power view function
**Root cause:** balanceOfNFT returns 0 when ownershipChange[_tokenId] == block.number for flash-NFT protection, but votingPowerOf iterates tokens calling internal _balanceOfNFT without that same-block guard.
**Steps:**
1. Read _transferFrom: it sets `ownershipChange[_tokenId] = block.number`.
2. Read balanceOfNFT: returns 0 if `ownershipChange[_tokenId] == block.number`.
3. Read votingPowerOf: loops ownerToNFTokenIdList and sums `_balanceOfNFT(_tokenId, block.timestamp)` with no ownershipChange check.
4. Acquire an NFT and call votingPowerOf in the same block: full voting power is returned despite the transfer.
5. Use that power in a voting integration built on votingPowerOf to influence a proposal within one transaction/block.
**How found:** Noticed the developer comment marking ownershipChange as flash-NFT protection, verified balanceOfNFT enforces the same-block zeroing, then checked the sibling votingPowerOf function and found the guard missing.
**Exploitation:** Precondition: a governance/voting integration consumes votingPowerOf. Attacker flash-borrows or borrows an NFT, transfers it to themselves, and in the same block calls votingPowerOf to obtain full voting weight, then votes before repaying/returning the NFT.
**Insight:** When a protocol adds a same-block transfer guard to one balance/weight getter, audit every other getter that reads the same per-token state; view functions feeding off-chain or future governance integrations often skip the guard.
