Open code423n4 opened 2 years ago
We plan to keep an eye on the number free validators and have a decent sized buffer of them.
This could be a duplicate of #338 , however the warden describes a different issue:
If the admin adds an incorrect or a duplicate validator, then depositEther will revert. It will stay disabled until the owner comes after a few hours to remove the validator causing problems.
There is no mention of a malicious owner wanting to DoS on purpose depositEther
- which is the only reason an admin would purposefully add a duplicate validator.
Lines of code
https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/OperatorRegistry.sol#L53 https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/frxETHMinter.sol#L140 https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/frxETHMinter.sol#L143
Vulnerability details
Impact
If the admin adds an incorrect or a duplicate validator, then
depositEther
will revert. It will stay disabled until theowner
comes after a few hours to remove the validator causing problems. In the worst case, sincefrxETHMinter
holds funds, the team could choose to set theowner
to the zero address. In this case the frax timelock contract has a total delay of execution of 16 days, at the end of which deposits could be resumed.Proof of Concept
For duplicate validators:
OperatorRegistry.addValidators()
and doesn't pay attention that in the array passed as an argument there is a duplicate.depositEther()
. It is registered to being active after deposit (activeValidators[pubKey] = true;
)depositEther()
is called the other duplicate validator is used, but this time the deposit will fail at the checkrequire(!activeValidators[pubKey], "Validator already has 32 ETH");
OperatorRegistry.removeValidator()
by:owner
a few hours latertimelock
16 days later ifowner
was previously set to zero addressFor an incorrect validator the description is similiar but
depositEther
fails at the call todepositContract.deposit
.Tools Used
Manual review
Recommended Mitigation Steps
Check for duplicate validators by declaring in
OperatorRegistry
:mapping(bytes => bool) public isValidator
Then add the check in
addValidator
:also add
isValidator[pubKey] = false;
each time a validator is popped.For incorrect validators, add a try/catch block around the call to
depositContract.deposit
+ remove the validator if the call fails: