Synthetix Logic Error Bugfix Review

Immunefi
Immunefi
Published in
3 min readJul 6, 2022

Summary

On May 2, 2022, whitehat thunderdeep14 submitted a critical bug in Synthetix via Immunefi, which the Synthetix team then shortly patched.

For his bug find, thunderdeep14 was paid $100,000, which is the max critical reward for Synthetix’s bug bounty program on Immunefi. Additionally, since Synthetix is eligible for matching payouts under Nexus Mutual’s Matching Program, the whitehat will be earning an additional $50,000, making his total payout $150,000.

Immunefi is pleased to have facilitated this responsible disclosure with our platform. Our goal is to make Web3 safer by incentivizing hackers to responsibly disclose bugs and receive clean money and reputation in exchange.

Now, on to an explanation about the vulnerability itself.

Vulnerability Analysis

Synthetix’s SIP 236 illustrates how fee reclamation and rebate features work in Synthetix.

One of the important features of the SIP is the following section:

The calculation of owing or owed is as follows:Amount * (1 — feeRate) * (srcRate/destRate — newSrcRate/newDestRate)If the result is negative, the amount is owed as a rebate.

This means that if the price of the destination token falls, the synth would rebate the destination token.

The vulnerability happens because Synthetix used the wrong variable, i.e., if the destination price decreases, then synth would rebate the difference in the destination token.

If a user were to call exchange before reclaiming their rebate, the exchange sourceAmount would be inflated. When an exchange occurs, the amount to be received by the user, amountReceived, is being calculated inside the internal function call to _exchange. Within _exchange, amountReceived is being assigned on [L486]:

amountReceived = _deductFeesFromAmount(entry.destinationAmount, entry.exchangeFeeRate);

If we look at how entry.destinationAmount is being calculated [L442], we see effectiveValueAndRatesAtRound is being called with the parameters sourceCurrencyKey, sourceAmount, destinationCurrencyKey, entry.roundIdForSrc, entry.roundIdForDest.

The vulnerability stems from passing the sourceAmount here instead of sourceAmountAfterSettlement. This means the full source amount (before the debts are applied) is being used to calculate the destination amount. When the call to _convert occurs, only the sourceAmountAfterSettlement is burned, but the amountReceived calculated from the full sourceAmount is being issued in the function.

To summarize, the function _exchange utilized the sourceAmount variable to calculate the amount that has to be rebated to the destination but did not do a post-reclaim check on it to see whether the amount is accurate relative to the dest token value.

To give an example of this vulnerability in action, let’s assume we are exchanging sUSD to sBTC, and the price of sBTC dropped in the cooldown period. Synth would rebate the difference amount in sBTC but the issue here is that the difference would be rebated in the destination token and synth failed to calculate the rebate value of sBTC in sUSD.

Vulnerability Fix

Synthetix fixed the vulnerability at the following commit.

Acknowledgements

We would like to thank thunderdeep14 for doing an amazing job and responsibly disclosing such an important bug. Big props also to the Synthetix team who responded quickly to the report and patched the bug.

If you’d like to start bug hunting, we got you. Check out the Web3 Security Library, and start earning rewards on Immunefi — the leading bug bounty platform for web3 with the world’s biggest payouts.

And if you’re feeling good about your skillset and want to see if you will find bugs in the code, check out the bug bounty program from Synthetix.

--

--

Immunefi
Immunefi

Immunefi is the premier bug bounty platform for smart contracts, where hackers review code, disclose vulnerabilities, get paid, and make crypto safer.