Ether Collateral Bug Disclosure
*No funds at risk*
There is an old saying in DeFi;
If samczsun hasn't found a bug in your code are you even on mainnet?
We are very thankful to Sam (@samczsun) for reviewing the Synthetix contracts and finding and a bug in our Ether Collateral contract yesterday. The code is deployed to mainnet but is not yet active, so no funds are at risk. The code requires an explicit switch from the protocolDAO and can only be activated at the end of the three month trial period which is two months away. Despite the code is not being active we have decided to pause new Ether Collateral loans until we can deploy a fix. Open loans will remain open and while we encourage everyone to close loans so we can deploy the updated contract there is no deadline to do so.
Synthetix has had an open bug bounty programme since early 2019, however, after review we feel that it is insufficient for the current size of the project so we have just updated the bug bounty tiers as follows:
- Informational: $100 sUSD
- Low severity: $500 sUSD
- Moderate severity: $1000 sUSD
- High severity: $5000 sUSD
Despite this code not being active we feel this is a high severity bug and will be paying Sam the updated bounty in line with the severity.
While the Ether Collateral contract upgrades were audited by Sigma Prime there was a misunderstanding as to the intent of the liquidation process specced in the SIP. In addition this was put through code review internally unfortunately this issue was missed and was not covered by our internal tests, this lack of test coverage is something we will address moving forward to ensure we increase test coverage from 95%+ to 100%.
We will be working closely with our audit partners Sigma Prime and Iosiro in the future to ensure we minimise the possibility for future incidents such as this through clearer communication.
The specific technical details of the disclosure are below:
On line 345 of the _closeLoan private function, the borrowed sETH is burned with the following code.
synthsETH().burn(account, synthLoan.loanAmount);
This currently works on the closeLoan public function as account
is the loan creators wallet address. For liquidations this should be msg.sender
.
After the 3 month trial is complete we wanted all loans to be closed to prepare for the full implementation of Ether Collateral. The loanLiquidationOpen
flag can be turned on by the protocolDAO which would allow anyone with sETH to close any remaining unclosed loans and receive the borrowers ETH. This is expected to be sufficient incentive for borrowers to close all loans. If there were abandoned loans because a borrower had potentially lost all of their borrowed funds then there was still a mechanism to allow the sETH to be removed from the system and close the trial.
However since line 345 is set to account
which is the loan creators address it would both;
- require the liquidator to have the total sETH borrowed in their wallet address &
- require the borrower to still have the sETH in their wallet address
Only if both these conditions are met after the 3 month trial has ended and the ProtocolDAO has enabled loan liquidations then it would burn all of the borrowers sETH and send the ETH to the liquidator instead of burning the liquidators sETH.
This has rendered the liquidation mechanism defective and it can not be activated.
As soon as all loans are closed we can deploy a new version with the fix and continue the trial. However, we are not forcing loan closures to ensure we do not impact anyone with an open position during the trial.
If you would like to discuss this issue further please join us in discord.