In the frxETHMinter contract both the owner and governance timelock have the power to call the functions moveWithheldETH and recoverEther, those functions allow the transfer of the ETH from frxETHMinter to the owner or a given account, this means that the owner can easily call one of those functions to withdraw all the ETH balance and run with it which is basically a Rug Pull.
The impact of this is the following :
For the moveWithheldETH function the impact is lower as even if the owner rug pull the funds only the currentWithheldETH will be transferred which will of course remove the market liquidity but the other ETH funds intended for staking will be safe.
In the case of the recoverEther function the impact is much higher as the owner can call this function at any time and withdraw the full frxETHMinter contract ETH balance this will stop completely the staking process as there will be no ETH to be deposited and the users who held sfrxETHToken will not receive any rewards and won't be able to get their ETH back.
Proof of Concept
Both moveWithheldETH and recoverEther functions have the onlyByOwnGov modifier which means that they can be called either by the governance timelock or the owner at any time :
There are two solution to avoid the risk of a Rug pull :
The receiver of ETH funds in both moveWithheldETH and recoverEther functions should be set to the protocol treasury so even if the functions are called by the owner the ETH will be transferred to the treasury and not to another address.
The frxETHMinter contract should only allow the governance timelock to call the functions moveWithheldETH and recoverEther, this can be done by replacing the onlyByOwnGov modifier with an onlyByGov modifier.
Lines of code
https://github.com/code-423n4/2022-09-frax/blob/main/src/frxETHMinter.sol#L166-L174 https://github.com/code-423n4/2022-09-frax/blob/main/src/frxETHMinter.sol#L191-L196
Vulnerability details
Impact
In the
frxETHMinter
contract both the owner and governance timelock have the power to call the functionsmoveWithheldETH
andrecoverEther
, those functions allow the transfer of the ETH fromfrxETHMinter
to the owner or a given account, this means that the owner can easily call one of those functions to withdraw all the ETH balance and run with it which is basically a Rug Pull.The impact of this is the following :
For the
moveWithheldETH
function the impact is lower as even if the owner rug pull the funds only the currentWithheldETH will be transferred which will of course remove the market liquidity but the other ETH funds intended for staking will be safe.In the case of the
recoverEther
function the impact is much higher as the owner can call this function at any time and withdraw the fullfrxETHMinter
contract ETH balance this will stop completely the staking process as there will be no ETH to be deposited and the users who held sfrxETHToken will not receive any rewards and won't be able to get their ETH back.Proof of Concept
Both
moveWithheldETH
andrecoverEther
functions have theonlyByOwnGov
modifier which means that they can be called either by the governance timelock or the owner at any time :function moveWithheldETH
function recoverEther
Tools Used
Visual audit
Recommended Mitigation Steps
There are two solution to avoid the risk of a Rug pull :
The receiver of ETH funds in both
moveWithheldETH
andrecoverEther
functions should be set to the protocol treasury so even if the functions are called by the owner the ETH will be transferred to the treasury and not to another address.The
frxETHMinter
contract should only allow the governance timelock to call the functionsmoveWithheldETH
andrecoverEther
, this can be done by replacing theonlyByOwnGov
modifier with anonlyByGov
modifier.