The perpVaultLp contract is susceptible to a flash loan attack. An attacker can exploit the vulnerability by executing flash loan transactions using both the deposit() and redeem() functions. This allows the attacker to acquire extra rdpx tokens and increase their share of assets within seconds, all without actually adding a balance to the perpVaultLP. The attacker only needs to obtain a flash loan of weth as the deposit asset, and then they can use the deposit function to mint shares and subsequently call the redeem function to receive the flash loan amount along with additional rdpx tokens.
proof of concepts
The deposit function allows users to deposit assets (weth or rdpx) into the perpVaultLp contract. Since this function is public and accessible to any users, it can be exploited by an attacker. Here's a portion of the deposit function:
function deposit(
uint256 assets,
address receiver
) public virtual returns (uint256 shares) {
// Check for rounding error since we round down in previewDeposit.
require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");
perpetualAtlanticVault.updateFunding();
// Need to transfer before minting or ERC777s could reenter.
collateral.transferFrom(msg.sender, address(this), assets);
_mint(receiver, shares);
_totalCollateral += assets;
emit Deposit(msg.sender, receiver, assets, shares);
}
The redeem function allows users to redeem their assets by burning their shares and receiving extra rdpx tokens.
function redeem(
uint256 shares,
address receiver,
address owner
) public returns (uint256 assets, uint256 rdpxAmount) {
perpetualAtlanticVault.updateFunding();
if (msg.sender != owner) {
uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) {
allowance[owner][msg.sender] = allowed - shares;
}
}
(assets, rdpxAmount) = redeemPreview(shares);
// Check for rounding error since we round down in previewRedeem.
require(assets != 0, "ZERO_ASSETS");
_rdpxCollateral -= rdpxAmount;
beforeWithdraw(assets, shares);
_burn(owner, shares);
collateral.transfer(receiver, assets);
IERC20WithBurn(rdpx).safeTransfer(receiver, rdpxAmount);
emit Withdraw(msg.sender, receiver, owner, assets, shares);
}
in this case an attacker can:
Use a contract to obtain a substantial amount of weth through a flash loan.
Call the deposit function to update the _totalCollateral and mint shares corresponding to their weth balance.
In the same transaction, call the redeem function to redeem the weth, essentially paying back the flash loan. Simultaneously, the attacker receives an amount of rdpxAmount.
This attack can have a substantial impact as it effectively causes the protocol to grant the attacker a large quantity of rdpx tokens without any meaningful contribution.
Tools used
manual review
recommendation
I recommend implementing a delay mechanism for the deposited amount or restricting access to the deposit function to whitelist addresses only. These measures can help mitigate flash loan attacks and protect the protocol from such exploits
Lines of code
https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/perp-vault/PerpetualAtlanticVaultLP.sol#L118-L135 https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/perp-vault/PerpetualAtlanticVaultLP.sol#L145-L175
Vulnerability details
impact
The perpVaultLp contract is susceptible to a flash loan attack. An attacker can exploit the vulnerability by executing flash loan transactions using both the deposit() and redeem() functions. This allows the attacker to acquire extra rdpx tokens and increase their share of assets within seconds, all without actually adding a balance to the perpVaultLP. The attacker only needs to obtain a flash loan of weth as the deposit asset, and then they can use the deposit function to mint shares and subsequently call the redeem function to receive the flash loan amount along with additional rdpx tokens.
proof of concepts
The
deposit
function allows users to deposit assets (weth or rdpx) into the perpVaultLp contract. Since this function is public and accessible to any users, it can be exploited by an attacker. Here's a portion of the deposit function:The
redeem
function allows users to redeem their assets by burning their shares and receiving extra rdpx tokens.in this case an attacker can: Use a contract to obtain a substantial amount of weth through a flash loan.
Call the deposit function to update the _totalCollateral and mint shares corresponding to their weth balance.
In the same transaction, call the redeem function to redeem the weth, essentially paying back the flash loan. Simultaneously, the attacker receives an amount of rdpxAmount.
This attack can have a substantial impact as it effectively causes the protocol to grant the attacker a large quantity of rdpx tokens without any meaningful contribution.
Tools used
manual review
recommendation
I recommend implementing a delay mechanism for the deposited amount or restricting access to the deposit function to whitelist addresses only. These measures can help mitigate flash loan attacks and protect the protocol from such exploits
Assessed type
Other