Reentrancy leading to the unintended retention of token approvals, which can result in unauthorized token transfers
Summary
Vulnerability Detail
Approval Before External Call:
The contract approves _tx.target to spend _tx.value amount of tokens from the portal's balance.
This is done using IERC20(_nativeTokenAddress).approve(_tx.target, _tx.value);.
External Call to Target Contract:
The portal then makes a call to _tx.target using SafeCall.callWithMinGas.
If _tx.data.length != 0, the call is executed; otherwise, it skips the call.
Resetting the Approval:
After the call, the contract attempts to reset the approval back to zero using IERC20(_nativeTokenAddress).approve(_tx.target, 0);.
Potential Reentrancy and Revert Scenario:
If the target contract is malicious, it can deliberately cause the external call to revert.
Since the approval reset occurs after the external call, a revert will prevent the approval from being reset.
The approve function does not revert the initial approval, and the allowance remains set.
Exploiting the Unreset Approval:
With the approval still in place, the attacker can call transferFrom on the token contract to transfer tokens from the portal to an address of their choosing.
This effectively allows the attacker to drain tokens from the portal's balance.
Steps to Reproduce the Vulnerability
Craft a Malicious Target Contract:
The attacker deploys a contract that, when called, deliberately reverts the transaction.
Initiate a Withdrawal:
The attacker submits a withdrawal transaction where _tx.target is the address of their malicious contract and _tx.value is the amount of tokens they wish to steal.
Trigger the Vulnerable Function:
The attacker calls finalizeWithdrawalTransactionExternalProof with the crafted _tx.
Approval Remains Unchanged Due to Revert:
The external call to the malicious contract reverts.
The approval reset logic is not executed because the function reverts.
Drain Tokens Using Unreset Approval:
The attacker now has an active approval to spend _tx.value tokens from the portal's balance.
They call transferFrom on the token contract to transfer tokens from the portal to their own address.
Impact
Loss of Funds: The portal's token balance can be drained by attackers exploiting this vulnerability.
Reentrancy Risk: Although reentrancy is somewhat mitigated by the l2Sender check, the approval issue opens a vector for reentrancy-like attacks.
Albort
High
Reentrancy leading to the unintended retention of token approvals, which can result in unauthorized token transfers
Summary
Vulnerability Detail
Approval Before External Call:
_tx.target
to spend_tx.value
amount of tokens from the portal's balance.IERC20(_nativeTokenAddress).approve(_tx.target, _tx.value);
.External Call to Target Contract:
_tx.target
usingSafeCall.callWithMinGas
._tx.data.length != 0
, the call is executed; otherwise, it skips the call.Resetting the Approval:
IERC20(_nativeTokenAddress).approve(_tx.target, 0);
.Potential Reentrancy and Revert Scenario:
approve
function does not revert the initial approval, and the allowance remains set.Exploiting the Unreset Approval:
transferFrom
on the token contract to transfer tokens from the portal to an address of their choosing.Steps to Reproduce the Vulnerability
Craft a Malicious Target Contract:
Initiate a Withdrawal:
_tx.target
is the address of their malicious contract and_tx.value
is the amount of tokens they wish to steal.Trigger the Vulnerable Function:
finalizeWithdrawalTransactionExternalProof
with the crafted_tx
.Approval Remains Unchanged Due to Revert:
Drain Tokens Using Unreset Approval:
_tx.value
tokens from the portal's balance.transferFrom
on the token contract to transfer tokens from the portal to their own address.Impact
l2Sender
check, the approval issue opens a vector for reentrancy-like attacks.Code Snippet
https://github.com/sherlock-audit/2024-08-tokamak-network/blob/main/tokamak-thanos/packages/tokamak/contracts-bedrock/src/L1/OptimismPortal2.sol#L356
Tool used
Manual Review
Recommendation