Open hats-bug-reporter[bot] opened 1 month ago
A small note for the Revised Code section.
I noticed that there is also an admin function called addPairInfo
which also overwrites the state,
so I'd like to recommend a better solution to the issue, instead of checking whether the stableSwapPairInfo
for a certain set of tokens has been initialized within the functions createSwapPair
and createThreePoolPair
(i.e. in every function calling addPairInfoInternal
), it would be more efficient to do it directly in the addPairInfoInternal
function as follows:
function addPairInfoInternal(
address _swapContract,
address _t0,
address _t1,
address _t2,
address _LP
) internal {
+ require(stableSwapPairInfo[_t0][_t1][_t2].swapContract == address(0), "Stable pair already exists!");
StableSwapThreePoolPairInfo storage info = stableSwapPairInfo[_t0][_t1][_t2];
info.swapContract = _swapContract;
info.token0 = _t0;
info.token1 = _t1;
info.token2 = _t2;
info.LPContract = _LP;
swapPairContract[pairLength] = _swapContract;
pairLength += 1;
if (_t2 != ZEROADDRESS) {
addThreePoolPairInfo(_t0, _t1, _t2, info);
}
emit NewStableSwapPair(_swapContract, _t0, _t1, _t2, _LP);
}
Exploiting initialize vulnerability, this bug was found by #1 Regarding overriding when deploying pools, this is calculated by the admin so I think this is unlikely
Github username: -- Twitter username: -- Submission hash (on-chain): 0x71a37401edec58be04ad4746ea38e3c61ad8feec52d6f03628a32b78c8104e01 Severity: high
Description: Description
The StableSwapFactory
createSwapPair
can be called with the same parameters on a different block and will create a new LP token alongside with a new pool contract, while overwritting the existing statestableSwapPairInfo
for the tokenA/tokenB/tokenC address. That can result into an existing pool being replaced by a new one.Furthermore, the
initialize
function can be called more than once which means anyone can overwrite the currentadmin
.A malicious actor can either exploit the vulnerability to DOS every pool, or steal funds from users trying to swap with
amountOutMin = 0
.The malicious actor calls
initialize
with the same parameters as the current one, changing the_admin
parameter to his address, then goes on and callscreateSwapPair
with the same parameters as the pool he wants to spoof, which overwritesstableSwapPairInfo
. Then, he adds liquidity to the new pool he created, with total liquidity 2 wei.The user's swap transaction either goes through and loses all the funds he tries to swap, or his swap gets reverted depending on the
amountOutMin
value.The vulnerability can be exploited to both twoPool and threePool.
Attack Scenario 1
exactInputStableSwap
withamountOutMin = 0
.initialize
on theStableSwapFactory
with the same parameter as the current one but changes the_admin
address to his own.createSwapPair
with parameters identical to the ones used to create the pool the user tries to swap, overwritting (spoofing) the pool instableSwapPairInfo
.add_liquidity
and adds 1 wei worth of each token as liquidity.remove_liquidity
draining the user's fund.Attack Scenario 2
exactInputStableSwap
withamountOutMin > 0
.initialize
on theStableSwapFactory
with the same parameter as the current one but changes the_admin
address to his own.createSwapPair
with parameters identical to the ones used to create the pool the user tries to swap, overwritting (spoofing) the pool instableSwapPairInfo
.add_liquidity
and adds 1 wei worth of each token as liquidity.Attachments
It is recommended to make use of the OpenZeppelin's
Initializable
Contract. Which will prevert reinitialization.Furthermore, the
createSwapPair
andcreateThreePoolPair
should check thatstableSwapPairInfo
has not state for the given token addresses.