Open code423n4 opened 1 year ago
0xSorryNotSorry marked the issue as primary issue
yahgwai marked the issue as sponsor acknowledged
yahgwai marked the issue as disagree with severity
Severity: Med or Low, as not possible to exploit. The maximum amount of increased weight that a user can gain is 1. Therefore they would need to heavily split their vote (1e18 times) in order to cause 1 ARB votes worth of difference. This makes the attack ineffective.
This is essentially a dust attack, and maybe could qualify as a "leak of value" type issue making me think M is the correct severity, although when one consider the likelihood I think QA / Low may be more appropiate.
Will downgrade to M for now and welcome more conversation on the topic during the QA process.
0xean changed the severity to 2 (Med Risk)
0xean marked the issue as satisfactory
0xean marked the issue as selected for report
Hi @0xean, I don't think this issue should be a medium severity finding, as it isn't even remotely close to exploitable at all.
The example above states that 1 vote corresponds to 1
, which is incorrect as it doesn't take decimals into account. 1 ARB token corresponds to 1 vote, and since ARB token has 18 decimals, 1 vote would actually be 1e18
.
This is further mitigated by the decreaseAmount
formula as its numerator actually increases when votes should have less weightage:
SecurityCouncilMemberElectionGovernorCountingUpgradeable.sol#L252-L255
uint256 decreaseAmount =
votes * (blockNumber - fullWeightVotingDeadline_) / decreasingWeightDuration;
// subtract the decreased amount to get the remaining weight
return _downCast(votes - decreaseAmount);
As blockNumber - fullWeightVotingDeadline_
is only a few decimals less than decreasingWeightDuration
, for an attacker to leverage rounding to gain a significant amount of votes, he would have to send an insane amount of transactions.
For example, at 99% of decreasing weight timeframe, for an attacker to have full weightage for 1 vote, he would have to send 10**18 transactions, which is extremely impractical. At this point, it is more logical for the attacker to just buy more ARB tokens with the amount he paid in transaction fees...
Would appreciate it if you could take a second look at this finding, thanks!
@MiloTruck - thanks for the response and agree that QA is probably the right outcome for this issue.
0xean changed the severity to QA (Quality Assurance)
0xean marked the issue as grade-a
0xean marked the issue as not selected for report
Lines of code
https://github.com/ArbitrumFoundation/governance/blob/c18de53820c505fc459f766c1b224810eaeaabc5/src/security-council-mgmt/governors/modules/SecurityCouncilMemberElectionGovernorCountingUpgradeable.sol#L252-L253
Vulnerability details
Impact
Decline in voting weight over time can be circumvented by splitting votes over multiple accounts and voting with the correct amount of votes
Proof of Concept
According to the Arbitrum documentation (https://forum.arbitrum.foundation/t/proposal-security-council-elections-proposed-implementation-spec/15425)
"The voting process is designed to encourage voters to cast their vote early. Their voting power will eventually decay if they do not cast their vote within the first 7 days:
0 - 7 days. Votes cast will carry weight 1 per token 7 - 21 days. Votes cast will have their weight linearly decreased based on the amount of time that has passed since the 7 day point. By the 21st day, each token will carry a weight of 0."
The implementation of the "votesToWeight" function in SecurityCouncilMemberElectionGovernorCountingUpgradeable.sol implements the time-based decrease of votes and discounts this from the votes given: https://github.com/ArbitrumFoundation/governance/blob/c18de53820c505fc459f766c1b224810eaeaabc5/src/security-council-mgmt/governors/modules/SecurityCouncilMemberElectionGovernorCountingUpgradeable.sol#L252-L255
But because of the reason that Solidity rounds fractional numbers down to the next lower integer the calculated decrease can round down to 0. See the following examples:
The blocks are the Ethereum blocks since block.number in Arbitrum is the synced Ethereum L1 block number. Ethereum has 7200 blocks/day (5 blocks/min 60 min/hour 24h/day = 7200 blocks/day
Part 1 of the voting period: 0-7 days (7 days) / full weight = 50400 blocks Part 2 of the voting period: 7-21 days (14 days) / linearly declining weight = 100800 blocks
start block = 20000000
end block = startblock + 7 days + 14 days end block = 20000000 + 50400 + 100800 = 20151200
full weight voting deadline = start block + 7 days full weight voting deadline = 20000000 + 50400 = 20050400
decreasing weight duration = end Block - full weight voting deadline decreasing weight duration = 20151200 - 20050400 = 100800
Decrease amount = votes * (block number - full weight voting deadline) / decreasing weight duration
1) Example at 25% of decreasing weight timeframe block = 20050400 + 0.25 (20151200 - 20050400) = 20075600 decrease amount = 3 (20075600 - 20050400) / 100800 = 0.75 -> rounds down to 0 Result: Voting at this block with 3 votes will not reduce the weight of the vote.
2) Example at 50% of decreasing weight timeframe block = 20050400 + 0.5 (20151200 - 20050400) = 20100800 decrease amount = 1 (20100800 - 20050400) / 100800 = 0.5 -> rounds down to 0 Result: Voting at this block with 1 vote will not reduce the weight of the vote.
3) Example at 75% of decreasing weight timeframe block = 20050400 + 0.75 (20151200 - 20050400) = 20126000 decrease amount = 1 (20126000 - 20050400) / 100800 = 0.75 -> rounds down to 0 Result: Voting at this block with 1 vote will not reduce the weight of the vote.
4) Example at 85% of decreasing weight timeframe block = 20050400 + 0.85 (20151200 - 20050400) = 20136080 decrease amount = 1 (20136080 - 20050400) / 100800 = 0.85 -> rounds down to 0 Result: Voting at this block with 1 vote will not reduce the weight of the vote.
4) Example at 99% of decreasing weight timeframe block = 20050400 + 0.99 (20151200 - 20050400) = 20150192 decrease amount = 1 (20150192 - 20050400) / 100800 = 0.99 -> rounds down to 0 Result: Voting at this block with 1 vote will not reduce the weight of the vote.
The examples above show that the time-based decrease in voting power can be circumvented with the right amount of votes chosen at the right amount in time. This allows an attacker to influence an election even close to the end of the voting period if he split his votes over many accounts. The decreased amount of cost/transaction on Arbitrum compared to Ethereum main net facilitates such an attack.
Tools Used
Manual review
Recommended Mitigation Steps
A minimum amount of votes could be used to prevent rounding down to a 0 time-based decrease in voting power.
Assessed type
Math