Platform: Code4rena
Start Date: 10/02/2022
Pot Size: $30,000 USDC
Total HM: 5
Participants: 24
Period: 3 days
Judge: harleythedog
Total Solo HM: 3
Id: 86
League: ETH
Rank: 9/24
Findings: 3
Award: $1,205.81
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: robee
Also found by: 0x1f8b, csanuragjain
https://github.com/code-423n4/2022-02-nested/blob/main/contracts/NestedRecords.sol#L111
Duplicate tokens can be added which could exceed maxHoldingsCount and thus rejecting all functions in Factory
function store( uint256 _nftId, address _token, uint256 _amount, address _reserve ) external onlyFactory { uint256 amount = records[_nftId].holdings[_token]; if (amount != 0) { require(records[_nftId].reserve == _reserve, "NRC: RESERVE_MISMATCH"); updateHoldingAmount(_nftId, _token, amount + _amount); return; } require(records[_nftId].tokens.length < maxHoldingsCount, "NRC: TOO_MANY_TOKENS"); require( _reserve != address(0) && (_reserve == records[_nftId].reserve || records[_nftId].reserve == address(0)), "NRC: INVALID_RESERVE" ); records[_nftId].holdings[_token] = _amount; records[_nftId].tokens.push(_token); records[_nftId].reserve = _reserve; }
Factory calls the store function (via say _submitOrder function) with _nftId as 1, Token as X and amount as 0 (This is possible if a custom operator returns amounts[0] as 0 )
Since amount is 0 so below happens:
records[1].holdings[X] = 0; records[1].tokens.push(X);
Now say Step 2 happens again that is store is again called with _nftId as 1, Token as X and amount as 0.
This time store mishandles the request since amount = records[_nftId].holdings[_token] =0 which means below statement will execute again
records[1].holdings[X] = 0; records[1].tokens.push(X);
records[1].holdings[X] is harmless and will simply overwrite value but records[1].tokens.push(X); will add a duplicate token X which is incorrect
This becomes bigger problem once token length reaches maxHoldingsCount, making the factory unusable
Make sure that token is not already existing before adding it
#0 - maximebrugel
2022-02-10T16:00:03Z
#1 - harleythedogC4
2022-02-27T06:31:15Z
Marking this as the main issue
#2 - harleythedogC4
2022-02-27T16:43:39Z
Upon second thought I am taking the other issue as the main issue.
90.9726 USDC - $90.97
Contract: https://github.com/code-423n4/2022-02-nested/blob/main/contracts/FeeSplitter.sol#L146
Attacker can call sendFees with a malicious token contract
This increases the share balance of malicious token for each stake holder
When stakeholders tries to withdraw there share of malicious token using releaseTokens, malicious contract will be called and code written by attacker will be executed (asking for unauthorized approvals, wasting Gas etc)
Contract: https://github.com/code-423n4/2022-02-nested/blob/main/contracts/FeeSplitter.sol#L175
#0 - maximebrugel
2022-02-10T15:25:24Z
Yes and no... Yes it can run malicious code in the transfer
function, but we can skip the token if we want.
Same logic can be applied to NestedFactory
. We can't really change that since we are not "whitelisting" tokens.
We are only sending fees with ERC20 (so WETH and not ETH). In the releaseTokens
tokens we are unwrapping the WETH to transfer ETH.
#1 - maximebrugel
2022-02-16T13:32:56Z
Fixed in https://github.com/code-423n4/2022-02-nested-findings/issues/70 commit
#2 - harleythedogC4
2022-03-01T02:14:35Z
My personal judgements:
#3 - harleythedogC4
2022-03-03T01:51:08Z
Also adding in the reduced severity finding #10: 4. "Royalty owner can steal Stakeholders fees". Just code consistency. Valid and non-critical.
#4 - harleythedogC4
2022-03-03T02:25:38Z
Now, here is the methodology I used for calculating a score for each QA report. I first assigned each submission to be either non-critical (1 point), very-low-critical (5 points) or low-critical (10 points), depending on how severe/useful the issue is. The score of a QA report is the sum of these points, divided by the maximum number of points achieved by a QA report. This maximum number was 26 points, achieved by https://github.com/code-423n4/2022-02-nested-findings/issues/66.
The number of points achieved by this report is 2 points. Thus the final score of this QA report is (2/26)*100 = 8.
🌟 Selected for report: pauliax
Also found by: 0x1f8b, Dravee, GreyArt, Omik, ShippooorDAO, Tomio, bobi, cmichel, csanuragjain, defsec, gzeon, kenta, kenzo, m_smirnova2020, rfa, robee, sirhashalot, ye0lde
90.0012 USDC - $90.00
require(amount!=0, "Incorrect amount");
if (tokens[tokenIndex] == _token) { ... return; }
#0 - adrien-supizet
2022-02-15T11:07:52Z
#1 - harleythedogC4
2022-03-13T02:20:00Z
My personal judgments:
return
seems to do the same thing as break
in this scenario. Valid and small optimization.#2 - harleythedogC4
2022-03-13T06:18:44Z
Now, here is the methodology I used for calculating a score for each gas report. I first assigned each submission to be either small-optimization (1 point), medium-optimization (5 points) or large-optimization (10 points), depending on how useful the optimization is. The score of a gas report is the sum of these points, divided by the maximum number of points achieved by a gas report. This maximum number was 10 points, achieved by #67.
The number of points achieved by this report is 2 points. Thus the final score of this gas report is (2/10)*100 = 20.