Platform: Code4rena
Start Date: 07/07/2022
Pot Size: $75,000 USDC
Total HM: 32
Participants: 141
Period: 7 days
Judge: HardlyDifficult
Total Solo HM: 4
Id: 144
League: ETH
Rank: 18/141
Findings: 8
Award: $1,216.93
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: kenzo
Also found by: 0x1f8b, bin2chen, codexploder, dipp, minhtrng, smiling_heretic
User can deposit funds by joining a non existent proposal id. Once the proposal with this id is created, user would have joined a proposal which they might not have wanted
Add below check to ensure that proposal actually exists
require(proposal.startTime>0, "No proposal found");
#0 - stevennevins
2022-07-20T18:34:41Z
Duplicate of #208
#1 - HardlyDifficult
2022-07-28T21:33:15Z
🌟 Selected for report: xiaoming90
Also found by: 0x52, Lambda, cccz, codexploder, hyh, kenzo, oyc_109, zzzitron
migrateVaultERC20/migrateVaultERC721 can lead to loss of all assets held by Vault
Add below check which make sure that Vault has been settled before migration
require(migrationInfo[_vault][_proposalId].newVault!=address(0),"Vault not settled");
#0 - stevennevins
2022-07-20T15:26:09Z
#1 - HardlyDifficult
2022-08-02T23:53:30Z
🌟 Selected for report: shenwilly
Also found by: 0x52, Lambda, MEP, Treasure-Seeker, TrungOre, codexploder, dipp, kenzo, panprog, smiling_heretic, xiaoming90, zzzitron
User funds can stuck in case where multiple proposal exist on same Vault
In withdraw function, allow user to withdraw fund if proposal was not committed. In short, proposal was not committed or proposal was inactive - then allow withdraw
#0 - stevennevins
2022-07-20T16:46:54Z
#1 - HardlyDifficult
2022-08-11T16:31:53Z
🌟 Selected for report: hansfriese
Also found by: 0x52, codexploder
User should not be allowed to join/leave a proposal if block.timestamp > proposal.startTime + PROPOSAL_PERIOD
Add below check to revert if proposal end time has reached
require(block.timestamp <= proposal.startTime + PROPOSAL_PERIOD, "Time has ended");
#0 - stevennevins
2022-07-22T10:18:12Z
Duplicate of #250
🌟 Selected for report: bbrho
Also found by: 0xNazgul, Saintcode_, codexploder, infosec_us_team, s3cunda, zzzitron
101.985 USDC - $101.98
The Merkle proof check can be bypassed by using fallback function which allows anyone to call _execute function (missing ACL checks). This allows attacker to execute plugins without caller being a module with permission to call or the owner.
Instead of calling_execute, call to execute should be made including proof sent by user
#0 - stevennevins
2022-07-19T15:45:08Z
We're confirming these issues around malicious owners exploiting delegation via the fallback and execute functions. The ownership of vaults isn't intended to be EOAs (in most situations) and we limited ownership access to installing plugins/delegation(as owner) at the protoform level, which we think could be more clear or additional limitations created in hindsight.
#1 - HardlyDifficult
2022-08-11T18:29:39Z
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x29A, Amithuddar, Avci, BowTiedWardens, Kthere, Limbooo, MEP, Ruhum, StyxRave, TomJ, Treasure-Seeker, TrungOre, Tutturu, Waze, bardamu, c3phas, cccz, codexploder, cryptphi, hake, horsefacts, hyh, oyc_109, pashov, peritoflores, scaraven, simon135, slywaters, sseefried, tofunmi, xiaoming90
1.3977 USDC - $1.40
The transfer function is bounded by 2300 gas limit. But some contract might need more than this gas which can lead to transfer failing
Use call instead of transfer
(bool success, ) = msg.sender.call{ethAmount}(""); require(success, "Transfer failed.");
#0 - 0x0aa0
2022-07-21T17:09:11Z
Duplicate of #325
#1 - HardlyDifficult
2022-07-28T15:49:10Z
Duping to #504
🌟 Selected for report: xiaoming90
Also found by: 0x1f8b, 0x29A, 0x52, 0xA5DF, 0xDjango, 0xNazgul, 0xNineDec, 0xf15ers, 0xsanson, 0xsolstars, 242, 8olidity, Amithuddar, Aymen0909, Bnke0x0, BowTiedWardens, David_, Deivitto, ElKu, Funen, Hawkeye, IllIllI, JC, Kaiziron, Keen_Sheen, Kthere, Kulk0, Kumpa, Lambda, MEP, ReyAdmirado, Rohan16, Ruhum, Sm4rty, TomJ, Tomio, Treasure-Seeker, TrungOre, Tutturu, Viksaa39, Waze, _Adam, __141345__, ak1, apostle0x01, asutorufos, async, ayeslick, aysha, bbrho, benbaessler, berndartmueller, c3phas, cccz, chatch, cloudjunky, codexploder, cryptphi, delfin454000, dipp, durianSausage, dy, exd0tpy, fatherOfBlocks, hake, hansfriese, horsefacts, hubble, joestakey, jonatascm, kebabsec, kenzo, kyteg, mektigboy, neumo, oyc_109, pashov, pedr02b2, peritoflores, rajatbeladiya, rbserver, robee, rokinot, s3cunda, sach1r0, sahar, sashik_eth, scaraven, shenwilly, simon135, sorrynotsorry, sseefried, svskaushik, unforgiven, z3s, zzzitron
61.9781 USDC - $61.98
Issue: In _deployVault function, it is not verified that length for _plugins and _selectors is same which means the loop will run incorrect number of times
Recommendation: Add below check
require(_plugins.length==_selectors.length, "Incorrect length");
Issue: In transferOwnership function, add a zero address check otherwise this vault becomes useless as no plugins can now be installed
Recommendation: Add below check:
require(_newOwner!=address(0), "zero address");
Issue: redeem function is burning the totalSupply from vault but is not transferring the amount back to caller
#0 - HardlyDifficult
2022-08-05T12:19:14Z
🌟 Selected for report: joestakey
Also found by: 0x1f8b, 0x29A, 0xA5DF, 0xKitsune, 0xNazgul, 0xNineDec, 0xalpharush, 0xkatana, 0xsanson, 0xsolstars, 8olidity, Avci, Bnke0x0, BowTiedWardens, Chom, Deivitto, ElKu, Fitraldys, Funen, IllIllI, JC, Kaiziron, Lambda, Limbooo, MEP, NoamYakov, PwnedNoMore, RedOneN, ReyAdmirado, Rohan16, Ruhum, Saintcode_, Sm4rty, TomJ, Tomio, TrungOre, Tutturu, Waze, _Adam, __141345__, ajtra, apostle0x01, asutorufos, benbaessler, brgltd, c3phas, codexploder, cryptphi, delfin454000, dharma09, djxploit, durianSausage, fatherOfBlocks, giovannidisiena, gogo, horsefacts, hrishibhat, hyh, ignacio, jocxyen, jonatascm, karanctf, kebabsec, kyteg, m_Rassska, mektigboy, oyc_109, pedr02b2, rbserver, robee, rokinot, sach1r0, sashik_eth, simon135, slywaters
37.4693 USDC - $37.47
Recommendation: royaltyInfo function: Revert if royaltyAddress[_id] is address(0) as in this case Royalty is not defined
Contract: https://github.com/code-423n4/2022-07-fractional/blob/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/FERC1155.sol#L339 https://github.com/code-423n4/2022-07-fractional/blob/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/FERC1155.sol#L363
Recommendation: _computePermitStructHash Function : Change to ++nonces[_owner] instead of nonces[_owner]++
Recommendation: PERMIT_TYPEHASH : Assigned operations to constant variables are re-evaluated every time.Expressions for constant values such as a call to keccak256(), should use immutable rather than constant
Same need to be done for other variables like DOMAIN_TYPEHASH etc
Recommendation: generateMerkleTree Function: Max leaves length allowed is 6. Instead of running the loop till leaves length, its better to check that length is within range
require(leaves<=6,"Incorrect length");
Recommendation: commit Function : If proposal is already committed then no need for going forward
require(!proposal.isCommited, "Proposal already committed");
Recommendation: getLeafNodes Function: We already know permissions.length is always 5 so array can be revised accordingly
for (uint256 i; i < 5; )
Recommendation: withdrawERC721 Function: Line 351-358 for Buyout.sol can be placed in local scope to avoid stack too deep. Same can be done for withdrawERC20
{ (, uint256 id) = IVaultRegistry(registry).vaultToToken(_vault); if (id == 0) revert NotVault(_vault); // Reverts if auction state is not successful (, address proposer, State current, , , ) = this.buyoutInfo(_vault); State required = State.SUCCESS; if (current != required) revert InvalidState(required, current); // Reverts if caller is not the auction winner if (msg.sender != proposer) revert NotWinner(); }