Skip to content

Latest commit

 

History

History
82 lines (44 loc) · 5.54 KB

085.md

File metadata and controls

82 lines (44 loc) · 5.54 KB

Passive Fuchsia Alpaca

Medium

Incomplete Token Approval Revocation After Liquidity Transfer in _addLiquidity Function

Summary

The contract under the _addLiquidityrevokes the approval from the router but does not revoke approval from the gauge contract after depositing the liquidity tokens.

Root Cause

The approval for LP tokens is granted to the gauge, but there is no corresponding line of code revoking this approval after the liquidity tokens are deposited. As a result, the contract grants the gauge perpetual approval, which goes against the principle of minimizing token allowances to reduce risk exposure.

Internal pre-conditions

  1. User needs to call _addLiquidity() to set approval for the gauge to be at least the amount of liquidity tokens deposited.

  2. Admin needs to configure the gauge contract to allow deposits for it to go from having no tokens to having liquidity tokens from the _addLiquidity() function.

  3. User needs to ensure that the liquidity tokens are not revoked from the gauge after they are deposited within the contract's execution context.

External pre-conditions

  1. Gas price needs to be exactly 100 gwei for the attack transaction to be economically viable (minimizing transaction costs).
  2. LP token price needs to increase by at least 10% after liquidity is added but before the attacker calls transferFrom(), making the LP tokens more valuable.
  3. Token A’s price needs to drop by at least 5% in a different liquidity pool, increasing the incentives for the attacker to remove liquidity.
  4. Gauge contract’s reward rate needs to be set to at least a 2x multiplier for staked LP tokens within the next block, creating a higher reward for staked LP tokens.
  5. Router or gauge needs to experience a high transaction volume of at least 100 transactions per minute, making it easier to hide the malicious transaction among legitimate ones.
  6. Network congestion needs to spike within the next 5 minutes, delaying user or operator response time to revoke the unapproved allowance.

Attack Path

  1. Step 1: User grants approval

    • The user calls approve() on both token A and token B to allow the router contract to spend their tokens for the purpose of adding liquidity. This sets allowance[tokenA] and allowance[tokenB] to at least the amountADesired and amountBDesired.
  2. Step 2: User adds liquidity

    • The user calls addLiquidity() on the router, supplying tokens A and B. The router contract uses the approved tokens to create a liquidity position and mints LP tokens for the user.
  3. Step 3: User transfers LP tokens to gauge

    • The user calls approve() on the LP token, granting the gauge contract permission to transfer their LP tokens. The user then calls transfer() to stake their LP tokens in the gauge contract, leaving no LP tokens in their wallet. However, the approval for LP tokens remains unrevoked after this transfer.
  4. Step 4: User fails to revoke approval

    • After transferring LP tokens to the gauge, the user neglects to call approve(lpToken, 0) to revoke the approval for the LP tokens, leaving an open allowance in the gauge contract (or other contracts with LP token allowances).
  5. Step 5: Attacker monitors approvals

    • The attacker monitors on-chain approvals, identifying users who have not revoked their LP token allowances after staking. The attacker's script listens for approve() events and targets users with open approvals.
  6. Step 6: Attacker calls transferFrom()

    • Using the unrevoked approval, the attacker calls transferFrom() on the gauge contract (or another contract with LP token allowances) to transfer the user's LP tokens to their own address or to a malicious contract.
  7. Step 7: Attacker removes liquidity

    • The attacker then calls removeLiquidity() on the router to convert the stolen LP tokens back into the underlying assets (token A and token B). These tokens are now in the attacker’s control.
  8. Step 8: Attacker profits

    • The attacker can now sell or use the stolen tokens as desired. If the LP token’s value or staking rewards are high, the attacker’s profit from the exploit increases.

Impact

  • The LP token holders (affected party) suffer an approximate loss of 100% of their staked liquidity, as the attacker is able to transfer all the LP tokens out of the gauge due to the unrevoked approval.
  • The attacker gains the full value of the stolen LP tokens, which can be converted back into the underlying assets (token A and token B) or staked for rewards. The exact value gained depends on the liquidity pool size and the LP token's value at the time of the attack. For example, if the user’s LP token value is 10 ETH, the attacker gains 10 ETH worth of tokens.

In case of a vulnerability path:

  • The LP token holders (affected party) cannot securely stake their tokens without the risk of losing them due to lingering, unrevoked approvals. This leaves them exposed to potential exploitation. Alternatively, they may suffer an approximate loss of up to 100% of their LP tokens if an attack is successfully executed against them.

PoC

No response

Mitigation

include an additional line of code that revokes the approval from the gauge after depositing the liquidity tokens, ensuring that once the tokens are staked, no further actions can be taken