Joyn contest - Ruhum's results

Launchpad for collaborative web3 media projects with blueprints, building blocks, and community support.

General Information

Platform: Code4rena

Start Date: 30/03/2022

Pot Size: $30,000 USDC

Total HM: 21

Participants: 38

Period: 3 days

Judge: Michael De Luca

Total Solo HM: 10

Id: 104

League: ETH

Joyn

Findings Distribution

Researcher Performance

Rank: 11/38

Findings: 5

Award: $1,046.64

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: cccz

Also found by: Ruhum, WatchPug, hickuphh3, kirk-baird, leastwood, pedroais, rayn, saian, wuwe1

Labels

bug
duplicate
3 (High Risk)
sponsor confirmed

Awards

103.9584 USDC - $103.96

External Links

Lines of code

https://github.com/code-423n4/2022-03-joyn/blob/main/splits/contracts/Splitter.sol#L149-L169 https://github.com/code-423n4/2022-03-joyn/blob/main/splits/contracts/Splitter.sol#L35

Vulnerability details

Vulnerability details

Impact

The Splitter contract is used to split up the creator's proceeds. By repeatedly calling the incrementWindow() function, a creator can steal the other's share of the proceeds.

Proof of Concept

Let's say the currentWindow is at 0.

The Splitter contract received 5e18 tokens that should be distributed between two parties. Both get 50% of the pot.

Alice creates a contract that fulfills the two require statements here: https://github.com/code-423n4/2022-03-joyn/blob/main/splits/contracts/Splitter.sol#L152-L159

After the contract got the tokens, Alice calls the incrementWindow() function using her contract twice. Creating two windows each with a pot of 5e18: https://github.com/code-423n4/2022-03-joyn/blob/main/splits/contracts/Splitter.sol#L149-L169

After that, Alice claims both windows using claimForAllWindows(): https://github.com/code-423n4/2022-03-joyn/blob/main/splits/contracts/Splitter.sol#L35

For both windows, she receives 50% of the window's pot. That's 2 * 0.5 * 5e18 == 5e18. Thus, she takes all the funds of the Splitter contract. There's nothing left for Bob the other creator.

Tools Used

none

Store the balance at the time of the window creation in a state variable. When increasing the window, only assign the difference between the new and the old balance to the window's pot. Otherwise, someone can create multiple windows with the same balance.

#0 - sofianeOuafir

2022-04-15T12:44:27Z

This is a problem that we intend to fix

#1 - deluca-mike

2022-04-22T03:51:49Z

Seems like a duplicate of #3, but this has different implications and a solution that could be implemented in parallel.

#2 - deluca-mike

2022-06-11T22:27:33Z

Duplicate of #3

Findings Information

🌟 Selected for report: kirk-baird

Also found by: Ruhum, hyh

Labels

bug
duplicate
3 (High Risk)
sponsor confirmed

Awards

724.5042 USDC - $724.50

External Links

Lines of code

https://github.com/code-423n4/2022-03-joyn/blob/main/splits/contracts/Splitter.sol#L35-L62 https://github.com/code-423n4/2022-03-joyn/blob/main/splits/contracts/Splitter.sol#L149-L169

Vulnerability details

Impact

This is somewhat related to my other submission: "Creator can steal other creator's split in Splitter contract".

But, now instead of a creator stealing the other's funds, the issue is that someone else can DOS the usage of claimForAllWindows. Since anybody is able to call incrementWindow() they can create so many windows that any calls to claimForAllWindows after that will always fail.

Proof of Concept

An attacker implements a contract that calls the incrementWindow() function: https://github.com/code-423n4/2022-03-joyn/blob/main/splits/contracts/Splitter.sol#L149-L169 The contract they use implements the necessary functions to pass the two require functions.

They use the contract to call the incrementWindow() function a larger number of times. After that, calls to the claimForAllWindows() function will result in a way too high amount value. A value that is higher than the contract's actual balance. Thus, any calls to the function will revert: https://github.com/code-423n4/2022-03-joyn/blob/main/splits/contracts/Splitter.sol#L61

Tools Used

none

Limit the access to the incrementWindow() function.

#0 - sofianeOuafir

2022-04-14T19:21:21Z

In my opinion, the severity level should be 3 (High Risk) instead of 2 (Med Risk) duplicate of #3

#1 - deluca-mike

2022-04-22T02:20:10Z

This is more a duplicate of #6, since it pertains to the possibility of claimForAllWindows being made prohibitively expensive, regardless if it's from an attacker abusing incrementWindow, or natural growth of currentWindow without claims.

Findings Information

🌟 Selected for report: hyh

Also found by: Ruhum, WatchPug, hubble, kirk-baird, leastwood, pedroais, rayn, saian, securerodd

Labels

bug
duplicate
3 (High Risk)
sponsor confirmed

Awards

70.1719 USDC - $70.17

External Links

Lines of code

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L78-L97

Vulnerability details

Impact

The CoreCollection.initialize() function can be called multiple times by the creator of the collection. It is used to configure the collection. A malicious owner can abuse that by retroactively changing certain configurations. They could increase the max supply of the collection. Or, they could frontrun a user's purchase and increase the mintFee draining the user's funds. They can also change the splitFactory value which is normally not configurable by the owner.

Proof of Concept

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L78-L97

    function initialize(
        string memory _collectionName,
        string memory _collectionSymbol,
        string memory _collectionURI,
        uint256 _maxSupply,
        uint256 _mintFee,
        address _payableToken,
        bool _isForSale,
        address _splitFactory
    ) external onlyOwner onlyValidSupply(_maxSupply) {
        _name = _collectionName;
        _symbol = _collectionSymbol;
        _baseUri = _collectionURI;
        maxSupply = _maxSupply;
        mintFee = _mintFee;
        payableToken = IERC20(_payableToken);
        isForSale = _isForSale;
        splitFactory = _splitFactory;
        initialized = true;
    }

The initialize() function only has two modifiers: onlyOwner() and onlyValidSupply(). The first prevents anybody but the owner from calling this function. The other enforces the maxSupply value to be > 0. There is no check whether the collection was already initialized. The first initialization is done by the CoreFactory contract here. After that, the ownership is transferred to the original caller here. Thus, the creator is able to call the initialize() function multiple times.

Now let's say a user wants to mint 5 NFTs. The initial mintFee is 1e18. For whatever reason the user approves more funds to the collection than necessary for that purchase. Let's say they approve 10e18. Maybe they want to buy more in another transaction. Who knows. The creator of the NFT collection searches the mempool for a situation like this. It frontruns the user's transaction and calls initialize() to set the mintFee to 2e18 instead. Now they can pull the whole 10e18 tokens from the user's wallet here.

Tools Used

none

Add the onlyUnInitialized() modifier to the initialize() function.

#0 - sofianeOuafir

2022-04-14T19:43:28Z

duplicate of #4

Findings Information

🌟 Selected for report: kirk-baird

Also found by: 0xDjango, Dravee, Ruhum, TomFrenchBlockchain, WatchPug, defsec, hubble, hyh, leastwood, minhquanym

Labels

bug
duplicate
3 (High Risk)
upgraded by judge

Awards

85.0569 USDC - $85.06

External Links

Judge has assessed an item in Issue #25 as High risk. The relevant finding follows:

Fees should have a boundary of 100% (10000): https://github.com/code-423n4/2022-03-joyn/blob/main/royalty-vault/contracts/RoyaltyVault.sol#L68

Otherwise the contract will try to transfer more than possible which will result in reverts: https://github.com/code-423n4/2022-03-joyn/blob/main/royalty-vault/contracts/RoyaltyVault.sol#L40

It might also be helpful the have an fixed upper boundary that doesn't allow the platform to collect more than a set amount of fees, e.g. 10%.

Findings Information

Awards

62.952 USDC - $62.95

Labels

bug
sponsor confirmed
QA (Quality Assurance)

External Links

Report

Don't ignore ERC20 transfer return values

You're ignoring the return value of an ERC20 transfer twice:

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreCollection.sol#L175

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/ERC721Payable.sol#L54

Either use SafeERC20 or check the return value as you do in other places in the code base.

Add a max boundary for the platform fee

Fees should have a boundary of 100% (10000): https://github.com/code-423n4/2022-03-joyn/blob/main/royalty-vault/contracts/RoyaltyVault.sol#L68

Otherwise the contract will try to transfer more than possible which will result in reverts: https://github.com/code-423n4/2022-03-joyn/blob/main/royalty-vault/contracts/RoyaltyVault.sol#L40

It might also be helpful the have an fixed upper boundary that doesn't allow the platform to collect more than a set amount of fees, e.g. 10%.

No connection between a project & collection

When creating a project with collections, there is no ID linking the collections to that specific project. Both entities exist independent of each other. There seems to be no way of associating them with each other after the creation (besides the emitted event).

https://github.com/code-423n4/2022-03-joyn/blob/main/core-contracts/contracts/CoreFactory.sol#L70-L99

#0 - sofianeOuafir

2022-04-14T22:25:09Z

Severity should be 3 - High risk

duplicate of #52, #9

#1 - deluca-mike

2022-04-22T08:08:51Z

"No connection between a project & collection" is a valid comment, but not necessary to fix.

#2 - deluca-mike

2022-04-22T08:14:06Z

Converted second issue to #138

#3 - deluca-mike

2022-04-22T08:15:57Z

For the 3rd item, warden is suggesting some mapping or variable that would allow correlating projects and collections without needing to rely solely on events.

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