Nouns Builder contest - Ch_301's results

A permissionless, governed protocol to deploy nouns-style DAOs complete with treasury, generative collections, and governance mechanisms.

General Information

Platform: Code4rena

Start Date: 06/09/2022

Pot Size: $90,000 USDC

Total HM: 33

Participants: 168

Period: 9 days

Judge: GalloDaSballo

Total Solo HM: 10

Id: 157

League: ETH

Nouns Builder

Findings Distribution

Researcher Performance

Rank: 12/168

Findings: 7

Award: $2,759.00

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: saian

Also found by: 0x4non, Ch_301, MEP, Picodes, PwnPatrol, R2, Soosh, davidbrai, izhuer, rotcivegaf, scaraven

Labels

bug
duplicate
3 (High Risk)

Awards

235.614 USDC - $235.61

External Links

Lines of code

https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/lib/token/ERC721Votes.sol#L216

Vulnerability details

Impact

Attacker could get type(uint192).max of voting weight So he can create a proposal() to withdraw an amount from the Treasury.sol and he can pass the proposalThreshold with no need to anyone

Proof of Concept

1- Attacker buy one NFT and transfer it to addr_1 2- addr_1 will delegate() to addr_2 3- now Attacker will buy another NFT and transfer it to addr_1. So he has two 2 NFTs on the same address addr_1 4- this time addr_1 will delegate() to addr_3 In this step the addr_2 has type(uint192).max of voting weight. How? 4.1- delegate()==>_delegate()==> _moveDelegateVotes() 4.2- _moveDelegateVotes() it takes 3 param 4.2.1- _from is addr_2. As we know his voting weight is only one 1. 4.2.2- _to is addr_3 4.2.3- _amount is the amount of addr_1 which is two 2 4.3- on _moveDelegateVotes() in the first block if (_from != address(0)) on the last line we have this calculation prevTotalVotes - _amount as we know _amount == 2 and prevTotalVotes == 1. So 1-2 is 2**256 - 1 because we have an unchecked block on this function 5- on _writeCheckpoint() the _newTotalVotes will be only type(uint192).max

Remove the unchecked block from _moveDelegateVotes()

#0 - GalloDaSballo

2022-09-25T21:18:48Z

Dup of #469

Findings Information

🌟 Selected for report: Soosh

Also found by: Ch_301, PwnPatrol, davidbrai

Labels

bug
duplicate
3 (High Risk)

Awards

1642.0344 USDC - $1,642.03

External Links

Lines of code

https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/lib/token/ERC721Votes.sol#L133-L135 https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/lib/token/ERC721.sol#L125-L151

Vulnerability details

Impact

With only one NFT the user can keep increasing the voting weight on different addresses

Proof of Concept

1- let’s say Alice has one NFT 2- he delegate() to Bob 3- Alice invoke transferFrom() to Richard 4- Richard invoke delegate() to Bob So now Bob has two voting weight We can keep doing this process until we achieve the voting weight that we need it

When someone invokes transferFrom() you need to undelegated his voting weight

Findings Information

🌟 Selected for report: davidbrai

Also found by: Ch_301, Chom, GimelSec, PwnPatrol, cccz, datapunk, elad, pauliax, rbserver

Labels

bug
duplicate
2 (Med Risk)

Awards

104.7173 USDC - $104.72

External Links

Lines of code

https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/governance/governor/Governor.sol#L128 https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/governance/governor/Governor.sol#L363

Vulnerability details

Impact

The proposer's voting weight still has not dropped below the proposal threshold but anyone can invoke cancel() successfully

Proof of Concept

On the propose() it just check if (getVotes(msg.sender, block.timestamp - 1) < proposalThreshold()) so you can creat a propose in two cases = or >.

1- Let's say Alice creates a proposal and their getVotes(msg.sender, block.timestamp - 1) == proposalThreshold() 2- Bob will invoke cancel() in this check

if (msg.sender != proposal.proposer && getVotes(proposal.proposer, block.timestamp - 1) > proposal.proposalThreshold) revert INVALID_CANCEL();

3- the first part msg.sender != proposal.proposer will be true and the cecond part getVotes(proposal.proposer, block.timestamp - 1) > proposal.proposalThreshold is false. Because when Alice creates their proposal he was have getVotes(msg.sender, block.timestamp - 1) == proposalThreshold() 4- Bob will cancel Alice even he’s voting weight still has not dropped below the proposal threshold

Even when Alice decides to invoke propose() he has getVotes(msg.sender, block.timestamp - 1) > proposalThreshold() but after that he can sell or transfer some tokens. He can be in this situation getVotes(msg.sender, block.timestamp - 1) == proposalThreshold()

if (msg.sender != proposal.proposer && getVotes(proposal.proposer, block.timestamp - 1) >= proposal.proposalThreshold) revert INVALID_CANCEL();

Findings Information

🌟 Selected for report: davidbrai

Also found by: Ch_301, Chom, PwnPatrol, bin2chen, cryptphi, pashov

Labels

bug
duplicate
2 (Med Risk)

Awards

205.2074 USDC - $205.21

External Links

Lines of code

https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/lib/token/ERC721Votes.sol#L184-L189

Vulnerability details

Impact

In case you want to undelegated your voting weight you need to reset the delegation[your_Addr ] == address(0) . But unfortunately this not working you will lose your voting weight

Proof of Concept

1- Alice delegated their voting weight to Bob 2- after that he decides to undelegated them to use all their own voting weight 3- Alice invoke delegate(address(0)) 4- on _moveDelegateVotes() _to param is address(0) so it can’t pass the check if (_to != address(0))

Add more checks on _delegate() so if _to == address(0) you need to set it to be _to == _from

#0 - GalloDaSballo

2022-09-25T21:06:05Z

Dup of #203

Findings Information

🌟 Selected for report: azephiar

Also found by: 0x52, 0xSmartContract, Ch_301, Tointer, __141345__, bin2chen, indijanc

Labels

bug
duplicate
2 (Med Risk)

Awards

161.6008 USDC - $161.60

External Links

Lines of code

https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/token/Token.sol#L154 https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/token/Token.sol#L207-L213

Vulnerability details

Impact

It effects on the number of votes required to be in favor of a proposal in order to reach a quorum We can see on Governor.sol

function quorum() public view returns (uint256) { unchecked { return (settings.token.totalSupply() * settings.quorumThresholdBps) / 10_000; } }

So its effects directly the proposal

Proof of Concept

On Token.sol Every mint() the totalSupply is incrented by one

do { // Get the next token to mint tokenId = settings.totalSupply++; // Lookup whether the token is for a founder, and mint accordingly if so } while (_isForFounder(tokenId));

But the burn() has no decrement ont

settings.totalSupply- -

#0 - GalloDaSballo

2022-09-16T23:23:15Z

Dup of #405

This check if (nCheckpoints != 0) is always true

Finding

File: /lib/token/ERC721Votes.sol if (nCheckpoints != 0) prevTotalVotes = checkpoints[_from][nCheckpoints - 1].votes; if (nCheckpoints != 0) prevTotalVotes = checkpoints[_to][nCheckpoints - 1].votes;

https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/lib/token/ERC721Votes.sol#L213 https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/lib/token/ERC721Votes.sol#L228

Missing check for address(0)

Finding

File: /lib/token/ERC721Votes.sol function _delegate(address _from, address _to) internal { address prevDelegate = delegation[_from]; delegation[_from] = _to;

https://github.com/code-423n4/2022-09-nouns-builder/blob/main/src/lib/token/ERC721Votes.sol#L179-L184

#0 - GalloDaSballo

2022-09-26T21:10:19Z

Address(0) L

Other is invalid <img width="576" alt="Screenshot 2022-09-26 at 23 10 10" src="https://user-images.githubusercontent.com/13383782/192381133-5cf5467d-12e5-4a8a-abf9-6b1588b84f70.png"> 0 ++ is 0 and then it becomes 1

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter