The onAfterRemoveLiquidity function in the UpliftOnlyExample.sol implementation does not include the onlyVault modifier, this allows any one to invoke the function under very specific conditions, an attacker can exploit this flaw to delete the FeeData array and remove users' bptAmount and tokenId.
This would leave users with a zero balance of BPT, rendering them unable to restore their liquidity.
The onAfterRemoveLiquidity function is designed to be invoked exclusively by the Vault, the absence of the onlyVault modifier creates a vulnerability where any one can call this function.
onAfterRemoveLiquidity is critical function that is called from Vault after router calls unlock function in Vault and then the Vault passes the parameters like bytes memory userData which is the address of the user who wants to remove liquidity.
But since the onAfterRemoveLiquidity has no onlyVault and the unlock function in Vault must be unlocked the attacker can call it directly from his contract.
Attack Visualization:
[Attacker Contract] --> [Vault::unlock] --> (Callback) --> [Attacker Contract] --> [onAfterRemoveLiquidity]
Path of the Attack:
Attacker Prepares the Exploit:
The attacker deploys a malicious contract with two functions:
callVaultUnlock: A function to invoke Vault.sol::unlock.
attackerUnlockCallback: A function designed to be called by the Vault during its callback process.
Attacker Initiates the Exploit:
The attacker invokes Vault.sol::unlock via their malicious contract using the callVaultUnlock function.
Vault Executes Callback:
The Vault.sol::unlock function completes part of its process and then executes a callback to the attacker's contract, invoking the attackerUnlockCallback function.
Attacker Executes the Exploit:
During the callback phase, the attacker's contract maliciously invokes the onAfterRemoveLiquidity function in UpliftOnlyExample.sol.
Impact:
As a result of the exploit:
Bob's Balancer Pool Tokens (BPT) or NFTs are all deleted.
Bob is left with zero balance, and his liquidity becomes irrecoverable.
PoC: Add this into https://github.com/Cyfrin/2024-12-quantamm/blob/main/pkg/pool-hooks/test/foundry/UpliftExample.t.sol
run: forge test --mt test_Delete_All_User_BPTs_Share -vvv
This vulnerability can lead to the following:
Malicious actors can call the function, simulating Vault behavior, and delete all users FeeData array which contains all information about BPT amount and tokenID.
Users loss their liquidity for ever.
Implement the onlyVault Modifier Update the onAfterRemoveLiquidity function to include the onlyVault modifier:
Likelihood: High, anyone, anytime. Impact: High, Loss of funds
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.