An attacker possesses the capability to exhaust the entirety of liquidity within the stable swap pools by manipulating the buy function, specifically by setting the asset_in parameter equal to the asset_out parameter #58
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
edited-by-warden
H-01
high quality report
This report is of especially high quality
primary issue
Highest quality submission among a set of duplicates
🤖_14_group
AI based duplicate group recommendation
selected for report
This submission will be included/highlighted in the audit report
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
Lines of code
https://github.com/code-423n4/2024-02-hydradx/blob/603187123a20e0cb8a7ea85c6a6d718429caad8d/HydraDX-node/pallets/stableswap/src/lib.rs#L787-L842
https://github.com/code-423n4/2024-02-hydradx/blob/603187123a20e0cb8a7ea85c6a6d718429caad8d/HydraDX-node/math/src/stableswap/math.rs#L40-L41
Vulnerability details
Impact
This vulnerability has been identified in the Stableswap pallet that could potentially drain all liquidity from all pools without any permissions. This vulnerability can be exploited by malicious actors, resulting in significant financial losses for both the protocol and liquidity providers .
severity : critical
Proof of Concept
The vulnerability lies in the
buy()
function, which can be exploited by settingasset_in
to an asset already present in the pool and subsequently settingasset_out
to the same asset. The function does not validate or prevent this input, allowing an attacker to receive the entire amount_out
without providing any correspondingamount_in
.Attack Flow :
the attacker call the function
buy
and specify theasset_in
equal toasset_out
, the function has no check that prevent this input to be passed .the function will calculate the
amount_in
that should be taken out from the user , so the function will usecalculate_in_amount
function as shown here , this function will callcalculate_in_given_out_with_fee()
function .the function
calculate_in_given_out_with_fee
here , will call the functioncalculate_in_given_out
to calculateamount_in
, and the finalamount_in
will be the amount calculated plus the fees , and the fees are calculated as the ratio of theamount_in
.in the function
calculate_in_given_out
since theasset_in
equal toasset_out
then thenew_reserve_in
will be equal to the old reservereserves[idx_in]
so theamount_in
,which is the difference between the new and the old reserves ,will be equal to zero . as shown here , and then the function will add 1 to theamount_in
.this will result in
amount_in = 1
and with the fee , it will be equal toamount_in = 1.001
If the attacker set
amount_out = 100_000_000_000_000
he will take them and only payamount_in = 1.001
.Coded POC to demonstrate the vulnerability
consider add this test into the test file
trade.rs
here , and see the logs resulted from this test .the logs will be
as shown here , Bob can drain almost all the liquidity of
asset_a
in the pool , and he can repeat this attack to drain all the assets exists in all the pools .Recommended Mitigation Steps
To mitigate this vulnerability, it is crucial to prevent the setting of
asset_in
equal to asset_out. This can be achieved by adding the following line to thebuy()
function:Integrating this check into the buy() function will effectively prevent attackers from draining liquidity from the pool.
Assessed type
Invalid Validation
The text was updated successfully, but these errors were encountered: