#43803 [SC-Low] Boolean success returned from address.call{value: amount}() not checked
Submitted on Apr 11th 2025 at 17:43:30 UTC by @kaysoft for Audit Comp | Spectra Finance
Report ID: #43803
Report Type: Smart Contract
Report severity: Low
Target: https://github.com/immunefi-team/Spectra-Audit-Competition/blob/main/src/router/Dispatcher.sol
Impacts:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Brief/Intro
The _dispatch(...)
function in Dispatch.sol use a low level call to transfer ETH for the Commands.TRANSFER_NATIVE
command but does not check the returned boolean value.
When Eth transfer through the low level call fails, the ETH is lost to the Router.sol contract. This can cause malicious users to setup bots to monitor the balance of the Router.sol contract for this kind of bug and immediately steal the ETH with the same execute function.
The following reasons can cause low level call to revert:
When the recipient is a contract but without receive() or fallback() function.
The recipient explicitly reverts the transaction maybe due to some conditions(require)
Vulnerability Details
The Router.sol inherits the Dispatch.sol contract.
The execute(...) function in the Router.sol can be used to transfer ETH to a recipient
address. This is done by the internal _dispatch() function.
However the issue is that after the low level call{value: amount}
to transfer ETH, the returned boolean success
is not checked to ensure it is true
and if not revert.
File: Dispatch.sol
function _dispatch(bytes1 _commandType, bytes calldata _inputs) internal {
...
} else if (command == Commands.TRANSFER_NATIVE) {
(address recipient, uint256 amount) = abi.decode(_inputs, (address, uint256));
@> (bool success, ) = payable(recipient).call{value: amount}("");
} else {
revert InvalidCommandType(command);
}
}
When sending ETH to the recipient
address fails, the bool success
returned is false
. In a situation where the ETH transfer fails, the ETH will be lost to the Router.sol contract.
Impact Details
Loss of ETher to the Router.sol contract which can be stolen by snipper bots that monitor the balance of the Router.sol contract.
Recommendation
Consider checking the returned bool success
this way:
File: Dispatch.sol
function _dispatch(bytes1 _commandType, bytes calldata _inputs) internal {
...
} else if (command == Commands.TRANSFER_NATIVE) {
(address recipient, uint256 amount) = abi.decode(_inputs, (address, uint256));
(bool success, ) = payable(recipient).call{value: amount}("");
++ require(success, "ETH transfer failed");
} else {
revert InvalidCommandType(command);
}
}
Proof of Concept
Proof of Concept
Alice calls the execute(...) function of Router.sol with 5 ETH and
receipient
which is a smart contract withoutreceive()
function. The command isCommands.TRANSFER_NATIVE
The 5 ETH is lost to the Router.sol contract
Bob already setup bots to monitor Router.sol balance
Immediately the balance of Router.sol is non zero Bob's bot steals the 5 ETH.
Was this helpful?