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.