The smart contract NativeMetaTransaction
, which supports meta transactions (transactions that allow users to submit transactions via relayers), contains a critical vulnerability in the executeMetaTransaction
function. This vulnerability is a reentrancy attack that can occur when the contract interacts with external contracts, specifically when using the low-level call
function to execute the user’s function signature. The contract does not adequately protect against reentrancy, which could be exploited by an attacker to manipulate the state or drain funds.
The vulnerability resides in the executeMetaTransaction
function, specifically at the following line:
This line of code makes an external call to address(this)
using the call
function, which is vulnerable to reentrancy.
The contract executes meta transactions, allowing a user to sign a transaction off-chain and have a relayer submit it to the blockchain. The relayer pays for the gas to execute the transaction, and the user can execute functions via executeMetaTransaction
.
The executeMetaTransaction
function performs a low-level call to the contract itself using the call
method. The key part that opens up the vulnerability is the use of the call
function to execute arbitrary user-defined function signatures:
This line allows the contract to delegate execution to another function, but it does so without checking for reentrancy. If the functionSignature
points to a function that makes another call back to executeMetaTransaction
(or any other function that interacts with external contracts), it could lead to a reentrancy attack.
Reentrancy attacks occur when an external call to another contract (or even to the contract itself) can trigger a function call that re-enters the contract in an unexpected manner. This could allow an attacker to re-execute executeMetaTransaction
multiple times within the same transaction, potentially exploiting vulnerabilities like manipulating state or draining funds.
A malicious user submits a meta transaction with a crafted function signature.
The contract executes the transaction, making an external call using call
.
If the function signature executes a call back into executeMetaTransaction
, the same code could be executed repeatedly before the nonce is updated, allowing the attacker to bypass the nonce check and potentially exploit the contract.
This is critical because the contract doesn't have any protection against reentrancy, which can lead to unintended behavior such as:
State manipulation: Reentrancy can bypass nonce increments, causing the same transaction to be executed multiple times.
Funds draining: If the contract is transferring funds or assets, an attacker can potentially call back into the contract multiple times, draining the contract’s balance.
The impact of this vulnerability is high. If exploited, the attacker can:
Bypass nonce checks: The nonce is incremented after the function call, but reentrancy can allow an attacker to reuse the same nonce multiple times, causing unauthorized execution of multiple transactions under the same signature.
Potential funds theft: If the contract interacts with external contracts that allow the transfer of funds, the attacker could drain the contract’s funds.
State manipulation: Since the contract does not update its state or enforce any reentrancy protection, the attacker could manipulate the contract's internal state in unintended ways.
This vulnerability could lead to serious financial losses if the contract holds significant assets or interacts with valuable external contracts.
Slither: A static analysis tool for Solidity that analyzes code for common vulnerabilities, including reentrancy. Slither did not specifically highlight this vulnerability but would help identify general issues related to function calls and external contract interactions.
MythX: A smart contract security analysis service that checks for various vulnerabilities, including reentrancy. However, it may miss certain reentrancy vulnerabilities if the contract uses call
in a non-standard way.
Manual Review: An in-depth manual review of the smart contract code, paying attention to external function calls, state changes, and the use of call
, led to the identification of this reentrancy risk.
To protect against reentrancy attacks, the contract should implement a reentrancy guard. The most common way to do this is by using a mutex (a flag that ensures that a function cannot be entered again before the first execution is complete).
Here is an example of how to implement a reentrancy guard:
transfer
or send
instead of call
for Ether TransfersIf the contract is transferring Ether, replace the low-level call
with transfer
or send
. These functions limit the gas forwarded to the recipient, thus preventing reentrancy. If the contract is not meant to transfer Ether, ensure the msg.value
is not being passed incorrectly.
Before interacting with external contracts, ensure they are trusted and safe. Implement checks on external calls and ensure they cannot cause reentrancy or other unexpected behaviors. Using well-established libraries like OpenZeppelin's ReentrancyGuard
can help mitigate these risks.
The NativeMetaTransaction
contract contains a severe reentrancy vulnerability in the executeMetaTransaction
function due to the use of the low-level call
method. This vulnerability could lead to attackers bypassing the nonce check, draining funds, or manipulating contract state.
By implementing reentrancy guards, using safer function calls like transfer
for Ether transfers, and ensuring thorough auditing of external interactions, this vulnerability can be mitigated.
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.