Closed code423n4 closed 1 year ago
0xSorryNotSorry marked the issue as primary issue
0xSorryNotSorry marked the issue as duplicate of #1035
Not a duplicate of #1035
toshiSat marked the issue as disagree with severity
toshiSat marked the issue as sponsor confirmed
Not high severity due to withdraw being only able to be accessed by SafEth contract. Even in warden's test it shows directly calling withdraw method. This is a valid issue though and we should use the mitigation steps provided by warden
You can still technically call it the same way through the general withdraw function, I only wrote the test this way because it was easier to show how it works.
You can still make this test case work by calling the withdraw function on the SafEth contract, I wrote the test this way to explicitly show what I meant, so I disagree that it is only because I am calling the withdraw function on SfrxEth directly.
Just to clear up any confusion, this bug relies on manipulating the balance of FRXETH on the derivative contract and that is never checked in SafEth or the derivative contract, so this bug always works wherever it is called from. The SFRXETH, a different ERC20 token, is used to report the balance to the SafEth contract.
It makes no difference if this is called from the SafEth contract or directly.
Just wanted to make sure this was clear.
Picodes marked the issue as not a duplicate
Picodes marked the issue as satisfactory
Picodes marked the issue as primary issue
Picodes marked the issue as selected for report
Picodes marked the issue as unsatisfactory: Invalid
I don't think this is a valid finding.
The warden shows that you could send tokens directly to the contract, and then the trade would happen with the full balance whereas the slippage is computed based on the input.
This is true, but how can you exploit this? In the described example it is not profitable:
"// observe that we sent 1000 to FRXETH to contract before // calling withdraw, and we actually deposited 200 initially // we get back 1190"
I don't see how this could be: the attacker is sending tokens that will then be swapped with essentially a 0 slippage, so is just wasting funds.
Lines of code
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/SfrxEth.sol#L74-L75
Vulnerability details
Impact
The max slippage in the
SfrxEth
derivative contract can by bypassed by sending FRXETH to the derivative contract before withdrawing, then, inside the withdraw call, the exchange function on the CRV pool is called with an inaccurate min_out value. This is inaccurate because the min_out is calculated with the amount passed by the SafEth contract, but the amount sent for trading is the FRXETH balance of the contract. It is easy to imagine a flash loan attack where a user can add FRXETH liquidity to the CRV pool to cause the slippage to increase, then by some loan on SafEth (which is easily possible because SafEth is a normal ERC20) they can sell themselves FRXETH for a cheaper price and come out with more at the end of the attack. This attack effectively makes it so that protocol sells FRXETH for cheaper than its actual value.Proof of Concept
The proof of concept is simple (did not demonstrate attack, but I did show slippage can easily exceed 1%): 1) deposit ETH to
SfrxEth
2) Then get FRXETH in some fashion (I just minted it for sake of the PoC) 3) Unbalance curve pool by depositing a large amount of FRXETH 4) Send some FRXETH toSfrxEth
contract 5) Call withdraw and observe that slippage has effectively been exceededTo do this I edited and added some interfaces added interface for IFrxEth
added some functions to curvepool interface
Then I added this test case to the
Derivatives
test suite inside ofSafEth.test.ts
Tools Used
I used solidity and test suites inside of repo
Recommended Mitigation Steps
This problem can easily be solved by changing the min_out calculation to be based on FRXETH balance rather than amount passed into the withdraw function inside of
SfrxEth.sol
change lines 74-75 to: