Summary
Contract Fees
does no check for initializing immutable variables to address(0)
in constructor. Setting staking to address(0) is possible and when someone calls sellProfits
function the amount is transferred as WETH doesn’t revert on transferring to address(0).
Vulnerability Details
Contract Fees
contract Fees {
address public immutable WETH;
address public immutable staking;
.
.
constructor(address _weth, address _staking) {
WETH = _weth;
staking = _staking;
}
function sellProfits(address _profits) public {
require(_profits != WETH, "not allowed");
uint256 amount = IERC20(_profits).balanceOf(address(this));
IERC20(WETH).transfer(staking, IERC20(WETH).balanceOf(address(this)));
}
}
PoC
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "../src/Fees.sol";
import {WETH} from "solady/src/tokens/WETH.sol";
contract TWETH is Test {
WETH weth;
function setUp() public {
weth = new WETH();
weth.deposit{value: 10 * 1e18}();
}
function testWeth() public {
assertEq(weth.balanceOf(address(this)), 10*1e18);
}
function testTransferToAddressZero() public {
src/Fees.sol::L43 IERC20(WETH).transfer(staking, IERC20(WETH).balanceOf(address(this)));
*/
weth.transfer(address(0), 1 * 1e18);
}
}
[PASS] testTransferToAddressZero() (gas: 34714)
Traces:
[34714] TWETH::testTransferToAddressZero()
├─ [29516] WETH::transfer(0x0000000000000000000000000000000000000000, 1000000000000000000 [1e18])
│ ├─ emit Transfer(from: TWETH: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], to: 0x0000000000000000000000000000000000000000, value: 1000000000000000000 [1e18])
│ └─ ← true
└─ ← ()
shows WETH does transferred amount to address(0).
Impact
User may loose funds.
Tools Used
Manual Code Review, Foundry
Recommendations
Add zero-address checks
constructor(address _weth, address _staking) {
+ require(_staking != address(0), "staking address can't be address(0)");
WETH = _weth;
staking = _staking;
}