Platform: Code4rena
Start Date: 03/05/2022
Pot Size: $75,000 USDC
Total HM: 6
Participants: 55
Period: 7 days
Judge: Albert Chon
Total Solo HM: 2
Id: 116
League: COSMOS
Rank: 6/55
Findings: 3
Award: $4,927.30
🌟 Selected for report: 0
🚀 Solo Findings: 0
https://github.com/code-423n4/2022-05-cudos/blob/main/solidity/contracts/Gravity.sol#L276
When batches are submitted by validators in the current valset, they are checked for validity based on signatures and cumulative powers. Each validator in the valset has an associated power which can give certain validators more voting power than others. For a batch to be valid, the cumulative power of all "YES" signatures needs to be greater than _powerThreshold
, which is set once during contract initialisation in the constructor.
In the constructor, there is a check for cumulative power here. However, when updating a valset, there is no check for the cumulative power of the new valset. Therefore it is theoretically possible to submit a valset that doesn't have enough cumulative power to succeed in any transactions, and then the bridge will be locked (since the valset can't be updated either).
In updateValset
there is no logic for checking the cumulative power of the new valset. See below for recommended actions to resolve this.
VSCode
A check for cumulative power of the new valset should be added to updateValset
:
uint256 cumulativePower = 0; for (uint256 i = 0; i < _newValset.powers.length; i++) { cumulativePower = cumulativePower + _newValset.powers[i]; if (cumulativePower > _powerThreshold) { break; } } require( cumulativePower > _powerThreshold, "Submitted validator set signatures do not have enough power." );
#0 - V-Staykov
2022-05-11T11:07:18Z
Duplicate of #123
🌟 Selected for report: p_crypt0
Also found by: 0x1337, GermanKuber, IllIllI, WatchPug, csanuragjain, danb, dirk_y, kirk-baird
https://github.com/code-423n4/2022-05-cudos/blob/main/solidity/contracts/Gravity.sol#L632-L638
Currently it is possible for the admin to pull all tokens belonging to the Gravity bridge. In normal circumstances this is probably fine, but if the admin account were compromised this would lead to the bridge being drained of locked funds. Furthermore, a contract that is liable to potential rugpulls is usually not trusted by users following multiple high profile rugpulls of other projects in the past.
The withdrawERC20
method here gives the admin the ability to send the full balance of the Gravity.sol
contract of any token to themselves.
VSCode
I assume this method exists in case the contract has to be updated and funds moved across to a new implementation. Thus, I see two potential solutions:
#0 - mlukanova
2022-05-10T14:28:47Z
Issue duplicate of https://github.com/code-423n4/2022-05-cudos-findings/issues/14
🌟 Selected for report: IllIllI
Also found by: 0x1337, 0x1f8b, 0xDjango, 0xkatana, AmitN, CertoraInc, Dravee, Funen, GermanKuber, GimelSec, Hawkeye, JC, MaratCerby, WatchPug, Waze, broccolirob, cccz, ch13fd357r0y3r, cryptphi, danb, defsec, delfin454000, dipp, dirk_y, ellahi, gzeon, hake, hubble, ilan, jah, jayjonah8, kebabsec, kirk-baird, m9800, orion, oyc_109, robee, shenwilly, simon135, sorrynotsorry
302.6663 USDC - $302.67
During my audit of this project I found 5 low priority findings in the Gravity.sol
contract that I think are worth mentioning:
Any whitelisted address can remove all other whitelisted addresses. This is in the manageWhitelist
method here. This pattern doesn't make sense to me since you only need 1 bad actor in the whitelist for this situation to occur. The offending address can then frontrun any attempts from the admin to remove them from the whitelist by adding new addresses to the whitelist. I decided not to mark this as medium severity since I can't see the whitelist being used anywhere yet. I would update this method to only be callable by the admin.
The comment strings explaining submitBatch
and updateValset
say "anyone can call this function", but in reality the msg.sender
has to be an orchestrator (i.e. one of the existing validators in the valset)
makeCheckpoint
has the following comment string:
// The format of the checkpoint is: // h(gravityId, "checkpoint", valsetNonce, validators[], powers[])
This should be updated to:
// h(gravityId, "checkpoint", valsetNonce, validators[], powers[], rewardAmount, rewardToken)
There is no check in checkValidatorSignatures
to confirm whether or not the array of validator powers is decreasing. The validators should be passed in as arguments in decreasing power order to optimise gas. If you wanted to enforce this you could add a check as you loop through the array to verify that the current power is less than the previous power (in the array). This might use more gas than the arrays being out of order though, depending on the length of the arrays.
Test fixtures are still there and should be removed (seems obvious but easily forgotten)
#0 - albertchon
2022-05-17T09:52:29Z
On point 2, actually anyone can call submitBatch and updateValset