//
DoS - Multiple Deployments with the Same Token
pulse profile imagepulse
Medium

Description

The _tokenOwner mapping allows a user to deploy multiple vesting contracts for the same token (tokenAddress) without restriction. This could result in a Denial of Service (DoS) scenario by overloading the contract storage or computational resources especially if malicious actors intentionally create excessive deployments.

Impact

Resource Exhaustion:

Deploying numerous vesting contracts for the same token could lead to storage and computation issues potentially slowing down or halting the system.
This could cause increased gas costs for legitimate users or make the contract unusable.

System Overhead:

Each vesting contract needs management and consumes contract resources. Without limits the system might degrade in performance.

Operational Complexity:

Managing multiple vesting schedules for the same token may create conflicts or confusion impacting the overall functionality.

Root Cause

The deployVesting function does not validate whether a vesting contract already exists for a given tokenAddress. The _tokenOwner mapping only checks if the caller is the token owner but imposes no restriction on the number of contracts deployable per token.

Recommendations

Restrict Single Deployment per Token:

Introduce a mapping to track deployed vesting contracts for each tokenAddress. Prevent multiple deployments for the same token.

+ mapping(address => address) private _deployedVesting; function deployVesting( address tokenAddress, uint256 startTime, uint256 endTime, uint256 steps, string memory vestingId ) external { require(_tokenOwner[msg.sender] == tokenAddress, "SS_VestingDeployer: caller is not the token owner"); + require(_deployedVesting[tokenAddress] == address(0), "SS_VestingDeployer: vesting already exists for this token"); require(tokenAddress != address(0), "SS_VestingDeployer: token address is zero"); require(startTime > block.timestamp, "SS_VestingDeployer: start time must be in the future"); require(startTime < endTime, "SS_VestingDeployer: start time must be before end time"); require(steps > 0, "SS_VestingDeployer: steps must be greater than 0"); require(manager != address(0), "SS_VestingDeployer: manager not set"); address newVesting = address( new SecondSwap_StepVesting( msg.sender, manager, IERC20(tokenAddress), startTime, endTime, steps, address(this) ) ); + _deployedVesting[tokenAddress] = newVesting; IVestingManager(manager).setSellable(newVesting, true); emit VestingDeployed(tokenAddress, newVesting, vestingId); }

Limit Deployments per Owner:

Restrict the number of vesting contracts a single owner can deploy within a specific timeframe to avoid excessive resource use.