28912 - [SC - Critical] Attackers can control the vote result and ampli...
Submitted on Mar 1st 2024 at 17:54:55 UTC by @offside0011 for Boost | ZeroLend
Report ID: #28912
Report type: Smart Contract
Report severity: Critical
Target: https://github.com/zerolend/governance
Impacts:
Manipulation of governance voting result deviating from voted outcome and resulting in a direct change from intended effect of original results
Description
Brief/Intro
There is on lock on PoolVoter.sol. The voting results can be manipulated by repeatedly staking and unstaking in OmnichainStaking.
Vulnerability Details
Users can obtain NFTs by locking their zero tokens in either lockerLp or lockerToken. After acquiring the NFT, they can stake it in the OmnichainStaking to earn the corresponding token. Subsequently, they gain the ability to vote through PoolVoter, allowing them to control the share of the respective pool. When users vote, the PoolVoter.sol directly uses their balance in OmnichainStaking to determine their voting weight.
function _vote(
address _who,
address[] memory _poolVote,
uint256[] memory _weights
) internal {
// require(ve(_ve).isApprovedOrOwner(msg.sender, _tokenId));
_reset(_who);
uint256 _poolCnt = _poolVote.length;
uint256 _weight = staking.balanceOf(_who);
uint256 _totalVoteWeight = 0;
uint256 _usedWeight = 0;Although there are some checks in OmnichainStaking to avoid transfer between users
This check can be bypassed by unstaking directly and then staking it for another user.
Impact Details
The voting results can be manipulated and amplified, and the gauge pool rewards weight is based on the results of the voting. Therefore, attackers can exploit this to gain additional profits.
TIP1: Through auditing the code, another issue in the profit distribution process may be discovered. By manipulating the voting ratio at that moment, attackers can gain more profits. However, this second vulnerability would be analyzed more after fixing the first one.
TIP2: There is a bug in PoolVoter.sol, the bool check is wrong
TIP3 Another bug in voters.ts, the
governance.vestedZeroNFT.targetandlending.protocolDataProvider.targetis wrong.
References
https://github.com/zerolend/governance/blob/main/contracts/voter/PoolVoter.sol#L98 https://github.com/zerolend/governance/blob/main/contracts/locker/OmnichainStaking.sol#L60
Proof of concept
Last updated
Was this helpful?