-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Owner's ability to set any arbitrary virtualReserves allowes him to steal users funds #829
Comments
0xSorryNotSorry marked the issue as primary issue |
Sandwich attack is a known risk and is documented in the code with a comment that even warns against it: https://github.com/code-423n4/2023-04-caviar/blob/main/src/PrivatePool.sol#L204. The slippage check in the router contract serves to protect against this. Sandwiching is an issue in almost all AMM designs. I'm not sure if this is valid or not. |
outdoteth requested judge review |
outdoteth marked the issue as sponsor acknowledged |
outdoteth marked the issue as sponsor disputed |
The router protects against this |
GalloDaSballo marked the issue as unsatisfactory: |
Lines of code
https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/PrivatePool.sol#L538-L545
Vulnerability details
Impact
The owner of PrivatePool has the ability to set the virtualReserve to any arbitrary value he wants. There is no upper or lower limit.
When the user makes a call to
buy()
orsell()
ofPrivatePool
, the owner can sandwich the user's transaction and set the virtualReserves in such a way that,-1. The user might have to pay a very big amount of
baseToken
to buy theNFTs
-2. The user might not receive any
baseToken
in return while selling theNFTs
In
EthRouter.sol
, there is slippage protection forbuy()
andsell()
, but the owner can sandwich attack the user's transaction, making sure the user will receive or pay the limit he provided in the argument.Proof of Concept
Assume,
Current
virtualBaseTokenReserves = 100e18
,virtualNftReserves = 40e18
-1. Alice calls
buy()
of PrivatePool withtokenWeights = 10e18
,-2. The attacker front-run her transaction and calls
setVirtualReserves()
, with a very high value ofvirtualBaseTokenReserves
or a very low value ofvirtualNftReserves
or both. There is no limit to function.- virtualBaseTokenReserves = 1000e18
- virtualNftReserves = 11e18
https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/PrivatePool.sol#L538-L545
-3. Alice's transaction goes through
- In buy, inputAmount is calculated using the following formula,
https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/PrivatePool.sol#L694-L706
- inputAmount = (10e18 * 1000e18) / (11e18 - 10e18)
- inputAmount = 10000e18
- So,
inputAmount
would be very high instead it should have been33.33e18
according to actual virtualreserve- Remember, Owner can always check user's balance and manipulate the price accordingly
-4. Owner set the virtualReserve to normal range
During
sell()
, the Owner can manipulate the reserve in such a way that the user will not receive anybaseToken
in return for theirNFTs
by lowering thevirtualBaseTokenReserves
or increasing thevirtualNftReserves
https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/PrivatePool.sol#L713-L724
Tools Used
Manual Review
Recommended Mitigation Steps
There should be some limit by which the owner can manipulate the reserve. Ideally it should follow xy=k
The text was updated successfully, but these errors were encountered: