Summary
The LoveToken::constructor
and Vault::initVault
expect addresses: LoveToken
: one for the airdrop vault and one for the staking vault, and Vault
: one for managerContract. However, there could be injections of zero addresses, and currently, there are no checks in place to resist this.
Lovetoken::constructor
:
@> constructor(ISoulmate _soulmateContract, address _airdropVault, address _stakingVault)
ERC20("LoveToken", "<3", 18)
{
soulmateContract = _soulmateContract;
airdropVault = _airdropVault;
stakingVault = _stakingVault;
}
Vault::initVault
:
@> function initVault(ILoveToken loveToken, address managerContract) public {
if (vaultInitialize) revert Vault__AlreadyInitialized();
loveToken.initVault(managerContract);
vaultInitialize = true;
}
Vulnerability Details
Zero Address Injection Proof
Place the following test code snippet into the test/unit/soulmateTest.t.sol file. Put it at the very bottom but before the last closing semicolon }
.
function test_zeroAddressInjection() public {
vm.startPrank(deployer);
vm.expectRevert();
new LoveToken(ISoulmate(address(soulmateContract)), address(0), address(0));
vm.stopPrank();
}
function test_zeroAddressInjection_two() public {
vm.startPrank(address(airdropVault));
vm.expectRevert(Vault.Vault__AlreadyInitialized.selector);
airdropVault.initVault(ILoveToken(address(loveToken)), address(0));
vm.stopPrank();
}
Open Your Bash Terminal
and execute the following commands one by one...
forge test --mt "test_zeroAddressInjection"
forge test --mt "test_zeroAddressInjection_two"
a. First Test: The test will get failed saying: [FAIL. Reason: call did not revert as expected] test_zeroAddressInjection() (gas: 775652)
b. Second Test: The test will get passed because of expected Revert Vault__AlreadyInitialized
but not because of address(0)
revert.
Impact
Zero addresses are nightmares. Due to the immutability of the LoveToken
and Vault
once they get deployed, there's no way to change it, and zero addresses could potentially break the LoveToken
and Vault
protocol or contract. If this were to happen, there would be no way to update the contract, leaving the only option of not using it.
Tools Used
Manual Review
Recommendations
One recommended mitigation code....
One recommended mitigation code....
Update The src/LoveToken.sol
like below...
...
...
...
error LoveToken__Unauthorized();
+ error LoveToken__ZeroAddressNotAllowed();
...
...
...
constructor(ISoulmate _soulmateContract, address _airdropVault, address _stakingVault)
ERC20("LoveToken", "<3", 18)
{
+ if (_airdropVault == address(0) || _stakingVault == address(0)) {
+ revert LoveToken__ZeroAddressNotAllowed();
+ }
soulmateContract = _soulmateContract;
airdropVault = _airdropVault;
stakingVault = _stakingVault;
}
...
...
...
Update The src/Vault.sol
like below...
...
...
...
error Vault__AlreadyInitialized();
+ error Vault__ZeroAddressNotAllowed();
...
...
...
function initVault(ILoveToken loveToken, address managerContract) public {
+ if (managerContract == address(0)) revert Vault__ZeroAddressNotAllowed();
if (vaultInitialize) revert Vault__AlreadyInitialized();
loveToken.initVault(managerContract);
vaultInitialize = true;
}