Closed c4-bot-1 closed 5 months ago
Picodes marked the issue as duplicate of #937
The scenario described here is a semi-duplicate of #937 because it has more preconditions (1 single LP) and misses the part that this can happen at every pool initialization.
Picodes marked the issue as partial-75
Picodes changed the severity to 3 (High Risk)
This issue is not a duplicate of #937 but instead a duplicate of #111. This issue and #111 are the only issues with this root cause so I believe they should be separated from #937 duplicates. Here is the reason - The root cause of #937 duplicates is that one can front-run a deposit and then swap for profit. However the root cause of this and #111 is that pools ratio can be manipulated and pools with different tokens can be manipulated by the same way. The way they can be manipulated is if either addedAmount0
or addedAmount1
is 0 and the other one is not (you can read the issue for more information). No front-running is used here. This is a completely different issue and I kindly ask this to be reevaluated and also upgraded to a full duplicate of #111 because the reasons the judge marked this as partial-75 are two - it has a precondition of 1 single LP and it misses the part that
this can happen at every pool initialization.
Being the author of #111 , I second @LyuboslavVeliev 's views.
Picodes marked the issue as unsatisfactory: Invalid
Picodes marked the issue as unsatisfactory: Invalid
Picodes marked the issue as unsatisfactory: Invalid
Picodes marked the issue as unsatisfactory: Invalid
@t0x1cC0de and @LyuboslavVeliev thanks for your comments. I can see how these 2 reports are different from the rest. However, unless I am missing something using minLiquidityReceived
correctly would prevent this from happening. In this case, this would be invalid. Let me know if I am missing something.
Thanks @Picodes for spending the time to re-analyze and dive deep into these overall class of issues. I have been reading your inputs and analysis made on the primary issue and others since the last few hours and I can now understand to some extent the perspective you are presenting for invalidation, which makes sense.
Keeping your comments in mind, I believe the differentiating factor and hence the vulnerability here is the fact that even after an "honest" first deposit has been made by Alice, Bob is able to mess up the reserve ratio.
I additionally draw your attention to the "Impact & Issue - 2" section of my report #111 which outlines this in a different style. I'm not sure if that is a unique issue or a dupe of some other issue, but that scenario seems to be still valid. Bob is not trying to front-run anyone and his attacks are not avoidable by minLiquidityReceived
fix. He still manages to gain shares while managing to avoid paying any token2.
I will be quite honest here, I haven't digested all the issues which have been grouped in this class and maybe somewhere you have already explained an invalidation reason despite the presence of the above points, so apologoes if this is a repetition. But from what little I could see, the "Impact & Issue - 2" seemed to be different.
Will trust you analysis and judgement.
Thank you!
Thanks @Picodes for answering! In my example of the issue the front-running part is not the most important. The issue described is that after a fair ratio is set in a pool, a malicious user can actually change this ratio without ever swapping. In my example the ratio of a pool went from 1:10,000 to 101:201, which is a huge difference. Now if we are close to the dust amount this ratio cannot be changed through swaps and even if swaps can bring back the ratio, the depositors of the pool lose a lot of value since they put tokens at the original ratio and now users are extracting value in a way different ratio. If a user who lets say put 1WBTC and 10,000DAI wants to withdraw after this change of ratio, he would be able to get just ~1WBTC and 1DAI. This is how a user loses his funds. So the impact of this issue is not that we can harm users by front-running their transactions but that we can change pool's ratio and this way fair users lose money + if close to the dust amount this pool becomes unusable since no one will deposit at this wrong ratio + if someone neglects the slippage protection and does deposit they will end up losing most of the tokens. I would just like to add that this can happen even if we have multiple depositors in the pool, the user however will need to spend more gas to perform this attack.
Thanks for taking the time! Best wishes!
Picodes marked the issue as not a duplicate
Picodes marked the issue as duplicate of #785
Thanks for your comments. Please check also the conversation on #785.
I am not convinced by the "loss of funds" scenarios. In theory, if the slippage is correctly set these scenarios are avoided and we are assuming here that users initializing pools are advanced players
so the only convincing scenario to me is the case where the ratio is so screwed that it'd be too expensive to arb the pool and make it usable again. To "unfreeze" the pool a user would need to add liquidity and then swap more than the dust amount before removing its liquidity. Assuming he does all this in a single tx so it can't be arbed, it seems doable.
In the absence of a convincing PoC showing a profitable attack in which a user correctly setting the slippage is losing funds, I won't validate this issue and its duplicate.
"If a user who lets say put 1WBTC and 10,000DAI wants to withdraw after this change of ratio, he would be able to get just ~1WBTC and 1DAI." this doesn't look correct to me - or it would cost a lot to the attacker
Lines of code
https://github.com/code-423n4/2024-01-salty/blob/main/src/pools/Pools.sol#L178-L183
Vulnerability details
Summary
Pools with low liquidity and different decimals can be manipulated by withdrawing an amount that rounds down one of the
reclaimed
variables to 0.Vulnerability details
When removing liquidity from a pool a user has to specify
liquidityToRemove
and then it adjusts the reclaimed amounts depending on the ratio of the pool. This can be problematic if the tokens have different decimals as one of the reclaimed amounts can round down to 0. If that happens we only take out liquidity from the other token's reserve. Let's look at an example to understand the issue:reserve
at 101 wei (this allows for easier manipulation)reclaimedA = 0
andreclaimedB!= 0
. This is calculated by this formula -(totalLiquidity / reserve0) - 1
This attack can be performed on pools that have multle owners as we are removing only from one of the reserves.
Proof of Concept
Add this test in
2024-01-salty\src\pools\tests\Pools.t.sol
Add this on topimport "forge-std/console.sol";
To run the test:COVERAGE="yes" NETWORK="sep" forge test --match-test testChangingRatioThroughWithdraw -vvv --rpc-url (your url)
In this test we see that Alice adjust the ratio to 101:201 even though at the beginning it was 1:10,000. Alice does this only by withdrawing liquidity. This is possible exactly because
reclaimedA = 0
reclaimedB != 0
.Pools can be manipulated even if we are not a sole depositor using the formula I provided above
(totalLiquidity / reserve0) - 1
. It would however cost more gas to be executed.Impact
This can either result in great loss for the depositer if they decide not to use the slippage control or the pool can become unusable because of incorrect ratio (another pool with the same tokens cannot be created)
Tools Used
Manual Review, VS Code, Foundry
Recommended Mitigation Steps
In
Pools::removeLiquidity
check if eitherreclaimedA
orreclaimedB
is 0 and if one is 0 we should revert.Assessed type
Math