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.