Both contracts InfinityExchange and InfinityStaker have a function rescueETH to allow an admin to rescue any ETH accidentally sent to the contracts.
However, this ETH rescue functionality does not work. The code expects ETH to be sent to this function and immediately forwards this same amount of ETH to the specified destination address leaving the remaining ETH balance of the contract untouched.
This is due to using msg.value instead of address(this).balance as the ETH amount to rescue.
function rescueETH(address destination) external payable onlyOwner {
(bool sent, ) = destination.call{value: msg.value}(''); // @audit-info use `address(this).balance` to figure out current ETH balance
require(sent, 'Failed to send Ether');
}
function rescueETH(address destination) external payable onlyOwner {
(bool sent, ) = destination.call{value: msg.value}(''); // @audit-info use `address(this).balance` to figure out current ETH balance
require(sent, 'failed');
}
Tools Used
Manual review
Recommended mitigation steps
Consider using the current contract ETH balance. Change the function to (also remove payable):
Lines of code
https://github.com/code-423n4/2022-06-infinity/blob/765376fa238bbccd8b1e2e12897c91098c7e5ac6/contracts/staking/InfinityStaker.sol#L345-L349 https://github.com/code-423n4/2022-06-infinity/blob/765376fa238bbccd8b1e2e12897c91098c7e5ac6/contracts/core/InfinityExchange.sol#L1229-L1232
Vulnerability details
Impact
Both contracts
InfinityExchange
andInfinityStaker
have a functionrescueETH
to allow an admin to rescue any ETH accidentally sent to the contracts.However, this ETH rescue functionality does not work. The code expects ETH to be sent to this function and immediately forwards this same amount of ETH to the specified
destination
address leaving the remaining ETH balance of the contract untouched.This is due to using
msg.value
instead ofaddress(this).balance
as the ETH amount to rescue.Proof of Concept
InfinityStaker.rescueETH
InfinityExchange.rescueETH
Tools Used
Manual review
Recommended mitigation steps
Consider using the current contract ETH balance. Change the function to (also remove
payable
):