VTVL contest - Czar102's results

Building no-code token management tools to empower web3 founders and investors, starting with token vesting.

General Information

Platform: Code4rena

Start Date: 20/09/2022

Pot Size: $30,000 USDC

Total HM: 12

Participants: 198

Period: 3 days

Judge: 0xean

Total Solo HM: 2

Id: 164

League: ETH

VTVL

Findings Distribution

Researcher Performance

Rank: 35/198

Findings: 2

Award: $229.38

🌟 Selected for report: 2

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/token/VariableSupplyERC20Token.sol#L36-L46

Vulnerability details

Impact

The admin of the token is not constrained to minting maxSupply_, they can mint any number of tokens.

Proof of Concept

// If we're using maxSupply, we need to make sure we respect it
// mintableSupply = 0 means mint at will
if(mintableSupply > 0) {
	require(amount <= mintableSupply, "INVALID_AMOUNT");
	// We need to reduce the amount only if we're using the limit, if not just leave it be
	mintableSupply -= amount;
}

The logic is as follows: if the amount that can be minted is zero, treat this as an infinite mint. Else require that the minted amount is not larger than mintable supply.

One can note that it is possible to mint all mintable supply. Then the mintable supply will be 0 which will be interpreted as infinity and any number of tokens will be possible to be minted.

Tools Used

Manual analysis

Treat 2 ** 256 - 1 as infinity instead of 0.

#0 - 0xean

2022-09-23T23:49:27Z

The wardens logic is correct, but given that this behind an admin only flag there are some external factors that would need to come into play for this to be realized. Downgrading to M severity.

#1 - lucyoa

2022-09-27T18:11:34Z

IMHO vulnerabilities related to the protocol not working correctly or not as advertised should be considered high severity.

In this case advertised limited supply tokens do not work correctly and users are mislead. Imagine users buying tokens with "limited supply" and then info about the vulnerability becomes public leading to sell pressure and effectively loss for users.

Findings Information

🌟 Selected for report: Czar102

Also found by: 0xSmartContract, Lambda, Respx, csanuragjain, hansfriese, sashik_eth

Labels

bug
enhancement
2 (Med Risk)
sponsor acknowledged

Awards

228.641 USDC - $228.64

External Links

Lines of code

https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L394-L411

Vulnerability details

Impact

If the token is reentrant, an admin can steal all tokens locked in the VTVLVesting contract while having active locks.

In other words, due to this exploit possibility, the contract may be insolvent with respect to active vestings. Note that revoking claim doesn't break this invariant since the vesting is closed in that case.

Proof of Concept

The reentrancy in the vested token can be used by an admin if the execution can be hijacked before the balance change occurs.

/**
@notice Admin withdrawal of the unallocated tokens.
@param _amountRequested - the amount that we want to withdraw
	*/
function withdrawAdmin(uint112 _amountRequested) public onlyAdmin {    
	// Allow the owner to withdraw any balance not currently tied up in contracts.
	uint256 amountRemaining = tokenAddress.balanceOf(address(this)) - numTokensReservedForVesting;

	require(amountRemaining >= _amountRequested, "INSUFFICIENT_BALANCE");

	// Actually withdraw the tokens
	// Reentrancy note - this operation doesn't touch any of the internal vars, simply transfers
	// Also following Checks-effects-interactions pattern
	tokenAddress.safeTransfer(_msgSender(), _amountRequested);

	// Let the withdrawal known to everyone
	emit AdminWithdrawn(_msgSender(), _amountRequested);
}

Let's consider function withdrawAdmin. Firstly, the balance is checked and then if there is enough token surplus to withdraw, the withdrawal is allowed. The surplus is based on two values: numTokensReservedForVesting which isn't changed by this function and the balance of the contract.

If the owner hijacks the execution before the balance change in the token transfer (which is possible in, for example, ERC777), an admin can call this function again and it will allow for an invocation of another transfer since the token balance hasn't changed yet.

For example, if there is $1m in vestings in the contract, an admin can send $100k to it in tokens and recursively invoke withdrawalAdmin with the amount of $100k eleven times so that the whole contract balance will be drained.

Tools Used

Manual analysis

Add ReentrancyGuard's nonReentrant to the withdrawAdmin function.

#0 - 0xean

2022-09-24T20:55:16Z

This would require a number of assumptions to be the case including a malicious admin which the sponsors called out of scope. Because it is obviously not intended functionality, I am going to leave as M pending sponsor review. I think the non-reentrant modifier is worth adding.

#1 - lawrencehui

2022-10-07T15:14:32Z

Will consider adding ReentrancyGuard as suggested.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter