Platform: Code4rena
Start Date: 16/01/2024
Pot Size: $80,000 USDC
Total HM: 37
Participants: 178
Period: 14 days
Judge: Picodes
Total Solo HM: 4
Id: 320
League: ETH
Rank: 77/178
Findings: 3
Award: $90.94
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: falconhoof
Also found by: BiasedMerc, J4X, Rhaydden, cats, forgebyola, inzinko, jesjupyter, josephdara, zhaojie
79.2483 USDC - $79.25
Only whitelisted tokens can be used within the DAO, however the whitelisting process can be DOSed by malicious users using multiple addresses. Few facts about whitelisting tokens:
_openBallotsForTokenWhitelisting;
_openBallotsForTokenWhitelisting
In the function below, the length of the Enumerable array is checked:
function proposeTokenWhitelisting( IERC20 token, string calldata tokenIconURL, string calldata description ) external nonReentrant returns (uint256 _ballotID) { require( address(token) != address(0), "token cannot be address(0)" ); require( token.totalSupply() < type(uint112).max, "Token supply cannot exceed uint112.max" ); // 5 quadrillion max supply with 18 decimals of precision //@audit can dos whitelist process require( _openBallotsForTokenWhitelisting.length() < daoConfig.maxPendingTokensForWhitelisting(), "The maximum number of token whitelisting proposals are already pending" );
In the finalizeBallot()
function in the DAO.sol It first checks for the quorum using
require( proposals.canFinalizeBallot(ballotID), "The ballot is not yet able to be finalized" );
Then it verifies the approval in _finalizeTokenWhitelisting()
using:
if ( proposals.ballotIsApproved(ballotID ) )
Then it also verifies if it is the top in _finalizeTokenWhitelisting()
using:
// Fail to whitelist for now if this isn't the whitelisting proposal with the most votes - can try again later. uint256 bestWhitelistingBallotID = proposals.tokenWhitelistingBallotWithTheMostVotes(); require( bestWhitelistingBallotID == ballotID, "Only the token whitelisting ballot with the most votes can be finalized" );
Even if the protocol is willing to whitelist a malicious token, which would require people to vote it to the top. The malicious user can simply propose another contract with another address.
Manual Review
Create Proposal method to remove address from the _openBallotsForTokenWhitelisting
, or create an admin function to do this.
Other
#0 - c4-judge
2024-02-02T09:28:22Z
Picodes marked the issue as duplicate of #991
#1 - c4-judge
2024-02-14T07:54:22Z
Picodes marked the issue as satisfactory
🌟 Selected for report: juancito
Also found by: 0x3b, 0xBinChook, 0xCiphky, 0xHelium, 0xMango, 0xOmer, 0xRobocop, 0xSmartContractSamurai, 0xWaitress, 0xbepresent, 0xpiken, 7ashraf, Arz, Audinarey, Banditx0x, Bauchibred, Draiakoo, IceBear, J4X, Jorgect, Kaysoft, KingNFT, Rhaydden, Rolezn, The-Seraphs, Tigerfrake, Topmark, Tripathi, Udsen, ZanyBonzy, a3yip6, b0g0, chaduke, codeslide, csanuragjain, dharma09, djxploit, eta, ether_sky, grearlake, inzinko, jasonxiale, jesjupyter, josephdara, lanrebayode77, linmiaomiao, lsaudit, niroh, oakcobalt, peanuts, pina, sivanesh_808, slvDev, t0x1c, vnavascues, wangxx2026
11.6897 USDC - $11.69
The receive()
function in the ManagedWallet
contract is used to approve address changes. By sending greater than or equal to 0.05 ether to the contract, however after the confirmation, the confirmationWallet
can DOS the proposed Wallet forever by continuously sending 0.05 ether every 29 days. This prevents finalization as it continues shifting the activeTimelock
by 30 days on every call
In the receive function, the contract increases the timelock every time the confirmation wallet sends it over 0.05 ether.
// The confirmation wallet confirms or rejects wallet proposals by sending a specific amount of ETH to this contract receive() external payable { require( msg.sender == confirmationWallet, "Invalid sender" ); // Confirm if .05 or more ether is sent and otherwise reject. // Done this way in case custodial wallets are used as the confirmationWallet - which sometimes won't allow for smart contract calls. //@audit Medium confirmation wallet can DOS wallet change if ( msg.value >= .05 ether ) activeTimelock = block.timestamp + TIMELOCK_DURATION; // establish the timelock
Hence the activeTimelock
never ends.
Manual Review
Create a boolean value which returns true everytime the confirmation wallet has confirmed. it should return false after change or after rejection and it should be require in receive()
DoS
#0 - c4-judge
2024-02-02T13:59:09Z
Picodes marked the issue as primary issue
#1 - c4-sponsor
2024-02-12T21:35:38Z
othernet-global (sponsor) disputed
#2 - othernet-global
2024-02-12T21:36:09Z
Yes, the confirmationWallet by design has the ability to prevent changes to the managed wallet.
#3 - c4-judge
2024-02-21T12:36:06Z
Picodes changed the severity to QA (Quality Assurance)
#4 - Picodes
2024-02-21T12:36:20Z
Downgrading to QA as this is among the confirmationWallet's powers
#5 - c4-judge
2024-02-21T17:03:42Z
Picodes marked the issue as grade-b