Open c4-bot-3 opened 4 months ago
Hi @alex-ppg,
The validator has rejected the issue with the following rationale:
Working as intended as circumvented by lastEnd. Project admin should not commit such mistakes,Owner mistake in setting start and end. QA at best.
However, there is an incorrect assumption by the validator: the project admin is trusted.
ILOManager
is a general-purpose contract that can be used by any project for fundraising, not just Vultisig. So Owner of ILOManager
is trusted but Project Admin can be from any project (may or may not be trusted). Even in Readme here, there is no mention of Project owner to be trusted.
The essence of the documentation here is that any project can set up their ILO, and the locking of tokens will "adhere" to the vesting schedule.
The schedule mechanism in the code below implies that the Project Treasury's (or any other) vesting schedule must start after the end of the investor's vesting schedule, which is an important invariant from the investor's point of view. But This report shows how Project owners can break this invariant.
for (uint256 i = 0; i < scheduleLength; i++) {
// vesting schedule must not overlap
@-> require(schedule[i].start >= lastEnd, "VT");
lastEnd = schedule[i].end;
// we need to subtract fist in order to avoid int overflow
require(BPS - totalShares >= schedule[i].shares, "VS");
totalShares += schedule[i].shares;
}
So IMO, If ILOManager
was built only for Vultisig
, then this issue should have been QA as the validator suggested. However, the reported vulnerability allows an arbitrary project that might not be trusted to break the invariant (claim the tokens before investors and immediately after the launch). This is a straight forward Rug Pull Attack Vector and hence should be a valid issue.
Hey @Breeje16, thank you for the PJQA contribution. I will preface all validation repository finding responses by stating that they are not evaluated by judges directly and are only evaluated by the validators if they are deemed unsatisfactory.
The project administrator is a privileged role and the relevant SC guidelines around administrator mistakes apply here. Attempting to argue otherwise goes against the ethos of vulnerability reporting as vulnerabilities should always be reported in the category they are meant to.
This paragraph is included in all of my responses and confirms that no further feedback is expected in this submission as PJQA has concluded. You are free to refute any of my statements factually, however, I strongly implore you to do this with actual code references and examples.
Lines of code
https://github.com/code-423n4/2024-06-vultisig/blob/main/src/base/ILOVest.sol#L43
Vulnerability details
Impact
Stakeholders can bypass the vesting invariant and withdraw tokens early.
Proof of Concept
Vesting is a critical functionality provided by ILOPool for investors and the project.
During the initialization of
ILOPool
,vestingConfigs
are validated through the_validateSharesAndVests
function.The
_validateSharesAndVests
function calls_validateVestSchedule
to validate the vesting schedule.Here's the implementation of
_validateVestSchedule
:Important to note here:
schedule[i].start >= lastEnd
, the vesting schedule works correctly without overlap. However, it does not check ifschedule[i].end > schedule[i].start
.Without this check, the following scenario can occur:
schedule[i].start = 100
for a recipient when launch time ist = 80
.schedule[i].end
= 80.This bypasses the overlap check. Code Flow will be:
for
i = 0
:schedule[i].start >= lastEnd
is true aslastEnd
is0
initially.lastEnd
is set to80
.for
i = 1
:schedule[i].start
.This allows projects to bypass the vesting invariant and withdraw tokens early while Investors can be stuck with there tokens vested. Here's a proof of concept (PoC):
_getLinearVestingBypass
function inMock.t.sol
and updateschedule
in_getVestingConfigs
:testClaimPoC
function inILOPool.t.sol
:testClaimPoC
test ofILOPool.t.sol
:Result of Test:
The test successfully allowed the stakeholder (
TREASURY_RECIPIENT
in this case) to claim the tokens at launch time while investors still cannot withdraw funds until theVEST_START_0
period.Tools Used
VS Code
Recommended Mitigation Steps
Add validation in
_validateVestSchedule
to ensureschedule[i].end >= schedule[i].start
:Assessed type
Context