Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Reentrancy Attack Risk in sendETH Due to External Call to _to

## High-Risk Vulnerability Report: sendETH Function

Title: Reentrancy Attack Risk in sendETH Due to External Call to _to

Severity: High

Impact:

The sendETH function allows the contract owner to send ETH to an arbitrary address. However, it makes an external call to _to using .call{value: _amount}(""), which can trigger malicious fallback functions in untrusted contracts. This can lead to reentrancy attacks if the recipient contract makes a recursive call back into sendETH or other vulnerable functions within the contract.

Vulnerable Code:

function sendETH(uint256 _amount, address _to) external nonReentrant onlyOwner {
(bool success,) = _to.call{value: _amount}("");
require(success, "Transfer Failed");
_setDeadline();
}

Root Cause:

  • The function performs an external call to _to, which could be a malicious contract.

  • The nonReentrant modifier using transient storage may not fully prevent reentrancy if another contract interacts with the contract in an unexpected way before state updates.

  • The contract does not enforce any validation on _to, allowing ETH to be sent to arbitrary addresses, including potential attacker contracts.

Exploit Scenario:

  1. The contract owner calls sendETH to transfer ETH to an attacker-controlled contract (AttackerContract).

  2. AttackerContract has a fallback function that triggers another call back into the audited contract before sendETH completes execution.

  3. If other functions in the contract are vulnerable to reentrancy, the attacker may exploit them to drain funds or modify contract state unexpectedly.

Recommendation:

1. Use transfer or send Instead of .call{value: _amount}("")

Using .transfer or .send ensures that only 2300 gas is forwarded, preventing reentrancy attacks from complex fallback functions.

payable(_to).transfer(_amount);

However, this approach may fail if _to is a contract requiring more gas.

2. Update State Before External Calls

If .call must be used, ensure state-changing operations are performed before the external call to _to.

function sendETH(uint256 _amount, address _to) external nonReentrant onlyOwner {
_setDeadline(); // Update state before external call
(bool success,) = _to.call{value: _amount}("");
require(success, "Transfer Failed");
}

3. Implement Access Control or Safe Listing

Limit _to to a safe list of addresses or ensure it is an externally owned account (EOA) to reduce attack risk.

4. Consider Withdrawing Pattern

Instead of sending ETH directly, let recipients withdraw it themselves.

mapping(address => uint256) public balances;
function withdrawETH() external {
uint256 amount = balances[msg.sender];
require(amount > 0, "No ETH to withdraw");
balances[msg.sender] = 0;
payable(msg.sender).transfer(amount);
}

This prevents malicious fallback functions from executing within the same transaction.

Conclusion:

The sendETH function exposes the contract to reentrancy attacks due to an unprotected external call to _to. Immediate mitigation is required, either by using safer transfer methods, updating state before external calls, or adopting a withdrawal pattern.

Updates

Lead Judging Commences

0xtimefliez Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Wrong value in nonReentrant modifier

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.