MorpheusAI

MorpheusAI
Foundry
22,500 USDC
View results
Submission Details
Severity: low
Valid

`editPool` allows admin to set pool `payoutStart` in past, potential issue of premature claim and withdrawal can occur

Summary

In the editPool function of the Distribution contract, the vulnerability allows the admin to set the payoutStart parameter to a timestamp in the past, potentially enabling users to withdraw and claim rewards prematurely. The proposed fix involves introducing a validation check to ensure that payoutStart is always set to a future timestamp.

Vulnerability Details

In the editPool function, the absence of a validation check allows the admin to manipulate the payoutStart parameter, potentially setting it to a timestamp in the past. This vulnerability has a significant impact on the contract's security, as users may exploit the lower payoutStart value to withdraw and claim rewards before the intended timeframe.

Impact

The impact of this vulnerability is critical, as a lower or past value of payoutStart may lead to premature withdrawal and claiming of rewards by users.

However, the likelihood is low. Because the edit is controlled by admin only.

POC

  • Copy the below test and run it via forge test --match-test testEditPool -vvvv

  • In the result you can see when pool was created the payoutStart: 86400 and when the edit was done it is lowered to payoutStart: 56400

function testEditPool() public {
// create a new private pool
vm.prank(address(distribution.owner()));
distribution.createPool(myPool); // poolId = 0
vm.prank(address(distribution.owner()));
distribution.editPool(0, myPoolEdit);
}

Result:

├─ [184054] Distribution::createPool(Pool({ payoutStart: 86400 [8.64e4], decreaseInterval: 86400 [8.64e4], withdrawLockPeriod: 43200 [4.32e4], claimLockPeriod: 43200 [4.32e4], withdrawLockPeriodAfterStake: 86400 [8.64e4], initialReward: 100000000000000000000 [1e20], rewardDecrease: 20000000000000000000 [2e19], minimalStake: 10000000000000000000 [1e19], isPublic: true }))
│ ├─ emit PoolCreated(poolId: 0, pool: Pool({ payoutStart: 86400 [8.64e4], decreaseInterval: 86400 [8.64e4], withdrawLockPeriod: 43200 [4.32e4], claimLockPeriod: 43200 [4.32e4], withdrawLockPeriodAfterStake: 86400 [8.64e4], initialReward: 100000000000000000000 [1e20], rewardDecrease: 20000000000000000000 [2e19], minimalStake: 10000000000000000000 [1e19], isPublic: true }))
│ └─ ← ()
├─ [365] Distribution::owner() [staticcall]
│ └─ ← 0x0000000000000000000000000000000000000000
├─ [0] VM::prank(0x0000000000000000000000000000000000000000)
│ └─ ← ()
├─ [35540] Distribution::editPool(0, Pool({ payoutStart: 56400 [5.64e4], decreaseInterval: 86400 [8.64e4], withdrawLockPeriod: 43200 [4.32e4], claimLockPeriod: 43200 [4.32e4], withdrawLockPeriodAfterStake: 86400 [8.64e4], initialReward: 100000000000000000000 [1e20], rewardDecrease: 20000000000000000000 [2e19], minimalStake: 10000000000000000000 [1e19], isPublic: true }))
│ ├─ emit PoolEdited(poolId: 0, pool: Pool({ payoutStart: 56400 [5.64e4], decreaseInterval: 86400 [8.64e4], withdrawLockPeriod: 43200 [4.32e4], claimLockPeriod: 43200 [4.32e4], withdrawLockPeriodAfterStake: 86400 [8.64e4], initialReward: 100000000000000000000 [1e20], rewardDecrease: 20000000000000000000 [2e19], minimalStake: 10000000000000000000 [1e19], isPublic: true }))
│ └─ ← ()
└─ ← ()
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 13.15ms
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)

Recommendations

Introduce a validation check within the editPool function. Specifically, consider adding the following line of code to ensure that payoutStart is always set to a timestamp greater than the current block timestamp:

require(pool_.payoutStart > block.timestamp, "DS: invalid payout start value");
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

`editPool` function doesn't do the payoutStart check

Support

FAQs

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