The onTokenTransfer
function in the PriorityPool
contract does not adhere to the Checks-Effects-Interactions (CEI) pattern, potentially exposing the contract to reentrancy vulnerabilities.
The onTokenTransfer
function performs external calls to _deposit
, _withdraw
, and safeTransfer
without isolating these interactions after state changes. This lack of adherence to the CEI pattern could allow an attacker to exploit reentrancy vulnerabilities, especially if any of the called functions interact with untrusted contracts.
Unintended state changes could occur if reentrancy is exploited, leading to incorrect balances or unauthorized token transfers.
Manual Review
Users deposit tokens into the PriorityPool
to earn staking rewards.
The platform allows users to withdraw their tokens, either directly or by queuing them for later withdrawal.
The onTokenTransfer
function processes deposits and withdrawals but does not strictly adhere to the Checks-Effects-Interactions (CEI) pattern.
This could allow a reentrancy attack, where an attacker repeatedly calls the function to manipulate the contract's state or drain funds
The attacker calls the onTokenTransfer
function of PriorityPool
by transferring tokens from MaliciousContract
to PriorityPool
.
This triggers the onTokenTransfer
function, which proceeds to call _withdraw
if the msg.sender
is the stakingPool
.
Step 2: Reentrant Call
Inside _withdraw
, if there is an external call (e.g., to another contract or a callback), the MaliciousContract
exploits this to re-enter onTokenTransfer
.
The attacker uses this reentrant call to manipulate the state, such as increasing the queued tokens or withdrawing more tokens than allowed.
Step 3: Draining Funds
By repeatedly re-entering the contract, the attacker can manipulate the state to drain tokens from the PriorityPool
.
The attacker continues this loop until the contract's balance is significantly reduced or depleted.
Apply CEI pattern in the onTokenTransfer function
Added a check to ensure msg.sender
is either token
or stakingPool
before proceeding with any logic.
Introduced _processDeposit
and _processWithdrawal
internal functions to handle state changes separately.
Captured amountQueued
from _processWithdrawal
to use in the interaction phase.
Moved the safeTransfer
call to a distinct interaction phase after all state changes are complete, ensuring external calls are made only after internal state updates.
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.