Flaky Merlot Parrot
High
Excessive Refund Handling Will Cause Financial Loss for the Contract as Malicious Actors Exploit Unchecked Refunds
The unchecked handling of tokenInRefund
during refund execution in Brackets.sol: performUpkeep()
will cause financial loss for the contract as malicious actors can manipulate refund amounts to receive excessive tokens.
In Brackets.sol: performUpkeep()
, the following code:
//Brackets.sol: performUpkeep()
if (tokenInRefund != 0) {
order.tokenIn.safeTransfer(order.recipient, tokenInRefund);
}
processes refunds without validating whether tokenInRefund exceeds order.amountIn
, allowing refunds larger than the initial token input.
- Manipulated Refund Calculation:
- The tokenInRefund value is calculated in the
execute()
function, which lacks explicit safeguards against over-calculation.
- No Validation in Refund Execution:
- The
performUpkeep()
function transfers tokenInRefund directly without checking against order.amountIn.
1- Manipulated Execution Logic:
- External contracts or malicious actors manipulate the token flow to inflate
tokenInRefund
during the swap process.
- A malicious actor places an order with:
- A small amountIn (e.g., 10 tokens).
- The
execute()
function calculates a large tokenInRefund value through manipulation. - During performUpkeep, the following vulnerable code executes:
if (tokenInRefund != 0) {
order.tokenIn.safeTransfer(order.recipient, tokenInRefund);
}
- tokenInRefund exceeds order.amountIn, resulting in an excessive refund.
4- The attacker receives more tokens than they initially provided, causing a financial loss to the contract.
Excessive Refunds:
Refunds larger than order.amountIn
deplete contract funds.
Financial Loss: The contract or other users suffer financial losses due to manipulated refunds.
System Trust Issues: Unchecked refunds undermine user trust in the platform's reliability and fairness.
Vulnerable Logic
performUpkeep()
(Refund Execution):
//performUpkeep()
if (tokenInRefund != 0) {
order.tokenIn.safeTransfer(order.recipient, tokenInRefund);
}
- Issue: No validation ensures that
tokenInRefund
does not exceedorder.amountIn
.
2- execute()
(Refund Calculation):
//execute()
uint256 finalTokenIn = tokenIn.balanceOf(address(this));
tokenInRefund = amountIn - (initialTokenIn - finalTokenIn);
- Issue: If finalTokenIn is manipulated (e.g., through external contract calls), tokenInRefund can be artificially inflated.
-
Deploy a modified version of an external contract used in execute() that manipulates token balances.
-
Place an order with:
- amountIn = 10 tokens.
3 . Manipulate finalTokenIn
in the external contract to create an inflated tokenInRefund:
- tokenInRefund = 50 tokens.
- Observe the vulnerable refund logic in
performUpkeep()
transferring the manipulated amount.
Result:
The recipient receives 50 tokens instead of the initial 10 tokens.
Add a check to ensure tokenInRefund
does not exceed order.amountIn
:
+ require(tokenInRefund <= order.amountIn, "Refund exceeds initial amount");