Platform: Code4rena
Start Date: 22/09/2022
Pot Size: $30,000 USDC
Total HM: 12
Participants: 133
Period: 3 days
Judge: 0xean
Total Solo HM: 2
Id: 165
League: ETH
Rank: 12/133
Findings: 3
Award: $630.30
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: ladboy233
Also found by: 0xSmartContract, 8olidity, Aymen0909, Chom, IllIllI, OptimismSec, PaludoX0, TomJ, ayeslick, cccz, csanuragjain, joestakey, neko_nyaa, pashov, peritoflores, rbserver, rvierdiiev
19.982 USDC - $19.98
https://github.com/code-423n4/2022-09-frax/blob/main/src/frxETHMinter.sol#L191-L196
frxETHMinter.recoverEther
function sends all contract funds to the owner. I has onlyByOwnGov
modifier that allows it to be called by owner or timelock contract.
In case where the admin wallet has been hacked, the attacker can drain all funds. Or malicious owner can also send all funds to it.
I would recommend to allow to call that function only for timelock through the governance. Also i would change the function to take an address param as a sender to not send funds to owner only(in case when owner wallet is hacked for example).
Remove ability for the owner to send all funds to himself.
#0 - FortisFortuna
2022-09-25T21:23:13Z
We are well aware of the permission structure. The owner will most likely be a large multisig. We mentioned the Frax Multisig in the scope too. If moving funds, it is assumed someone in the multisig would catch an invalid or malicious address.
#1 - joestakey
2022-09-26T15:00:26Z
Duplicate of #107
🌟 Selected for report: ronnyx2017
Also found by: ayeslick, rvierdiiev
https://github.com/code-423n4/2022-09-frax/blob/main/src/frxETHMinter.sol#L166-L174
frxETH
is going to be stable coin to eth
that means that frxETH
should be backed 1:1
with ether.
frxETH
is minted by frxETHMinter
using _submit
function. It can be triggered by receive
function as well (that's important here).
frxETHMinter.moveWithheldETH
function allows to send some amount of currentWithheldETH
and then decrease the value that you can withdraw here and sends the value to the provided address to
.
If this function will be called(by mistake or no) with param to == address(frxETHMinter)
, then some amount of ether will be sent to frxETHMinter
, that will trigger receive
function and then more amount of frxETH
token will be minted and frxETH
token is not pegged to ether
as 1:1
anymore as we minted new frxETH
tokens without additional ether
supply.
This test was ran in frxETHMinterTest
.
It shows that after withdrawing to minter new frxETH
tokens were minted while balance of frxETHMinter
remain the same.
function testWithheldToMinter() public { vm.startPrank(FRAX_COMPTROLLER); vm.deal(FRAX_COMPTROLLER, 32 ether); // Set the withhold ratio to 50% (5e5) minter.setWithholdRatio(500000); // Deposit 32 ETH for frxETH vm.expectEmit(true, true, false, true); emit TokenMinterMinted(address(minter), FRAX_COMPTROLLER, 32 ether); vm.expectEmit(true, true, false, true); emit ETHSubmitted(FRAX_COMPTROLLER, FRAX_COMPTROLLER, 32 ether, 16 ether); minter.submit{ value: 32 ether }(); // Check that 16 ether was withheld assertEq(minter.currentWithheldETH(), 16 ether); //amount of frxToken before withdraw uint256 currentSupply = frxETHToken.totalSupply(); uint256 currentMinterBalance = address(minter).balance; minter.moveWithheldETH(payable(minter), minter.currentWithheldETH()); //note that also 50% were withheld assertEq(minter.currentWithheldETH(), 8 ether); //amount of frxToken after withdraw uint256 newSupply = frxETHToken.totalSupply(); uint256 newMinterBalance = address(minter).balance; //we have minted new tokens assertTrue(newSupply > currentSupply); //balance of minter hasn't changed assertTrue(newMinterBalance == currentMinterBalance); vm.stopPrank(); }
VsCode
Make sure that to
param is not the frxETHMinter
contract.
#0 - FortisFortuna
2022-09-26T00:22:32Z
We are well aware of the permission structure. The owner will most likely be a large multisig. We mentioned the Frax Multisig in the scope too. If moving funds, it is assumed someone in the multisig would catch an invalid or malicious address.
#1 - joestakey
2022-09-26T18:04:00Z
Duplicate of #221
🌟 Selected for report: rotcivegaf
Also found by: 0x040, 0x1f8b, 0x4non, 0xNazgul, 0xSmartContract, 0xf15ers, 8olidity, Aymen0909, B2, Bahurum, Bnke0x0, Ch_301, CodingNameKiki, Deivitto, Diana, Funen, IllIllI, JC, JLevick, KIntern_NA, Lambda, OptimismSec, PaludoX0, RockingMiles, Rolezn, Sm4rty, Soosh, Tagir2003, Tointer, TomJ, Triangle, Trust, V_B, Waze, Yiko, __141345__, a12jmx, ajtra, asutorufos, ayeslick, aysha, bbuddha, bharg4v, bobirichman, brgltd, bytera, c3phas, cryptostellar5, cryptphi, csanuragjain, datapunk, delfin454000, durianSausage, exd0tpy, gogo, got_targ, jag, joestakey, karanctf, ladboy233, leosathya, lukris02, mics, millersplanet, natzuu, neko_nyaa, obront, oyc_109, parashar, peritoflores, rbserver, ret2basic, rokinot, ronnyx2017, rvierdiiev, sach1r0, seyni, sikorico, slowmoses, tnevler, yasir, yongskiws
28.0141 USDC - $28.01
address
param for 0
address.
https://github.com/code-423n4/2022-09-frax/blob/main/src/frxETHMinter.sol#L60-L62
https://github.com/code-423n4/2022-09-frax/blob/main/src/OperatorRegistry.sol#L41
https://github.com/code-423n4/2022-09-frax/blob/main/src/ERC20/ERC20PermitPermissionedMint.sol#L34Validator stack is not empty
https://github.com/code-423n4/2022-09-frax/blob/main/src/OperatorRegistry.sol#L137require(!minters[minter_address], "Address already exists")
instead.
https://github.com/code-423n4/2022-09-frax/blob/main/src/ERC20/ERC20PermitPermissionedMint.sol#L68require(minters[minter_address], "Address nonexistant")
instead
https://github.com/code-423n4/2022-09-frax/blob/main/src/ERC20/ERC20PermitPermissionedMint.sol#L78