Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Invalid

Malicious Orchestrator Can Bypass Vesting Period Through Start Time Manipulation

Summary

The createVestingSchedule function in RAACReleaseOrchestrator contains a critical vulnerability where the startTime parameter can be manipulated by a malicious orchestrator to bypass or significantly reduce the vesting period. The function allows arbitrary setting of the start time without validation, enabling an orchestrator to set it to a past timestamp, which could make tokens immediately available after the cliff period.

https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/minters/RAACReleaseOrchestrator/RAACReleaseOrchestrator.sol

Problematic Implementation

function createVestingSchedule(
address beneficiary,
bytes32 category,
uint256 amount,
uint256 startTime
) external onlyRole(ORCHESTRATOR_ROLE) whenNotPaused {
// ...
schedule.startTime = startTime;
schedule.duration = VESTING_DURATION;
// ...
}

Vulnerability Details

The StartTime is set without any validation , hence can be set before the actual start time of the beneficiaries ;

Attack Scenario:

  1. An orchestrator sets startTime to current_timestamp - VESTING_DURATION

  2. This makes the vesting schedule appear to have already completed

  3. After the cliff period (90 days), tokens become immediately available

  4. The intended 700-day vesting period is effectively bypassed

Impact

  1. Complete bypass of vesting schedule timing

  2. Undermines the entire purpose of the vesting mechanism

  3. Affects all token categories (TEAM, ADVISOR, TREASURY, etc.)

  4. Total potential impact: 65.1% of token supply (65.1M RAAC tokens)

Tools Used

manual review

Recommendations

  1. Remove manual start time setting and use current block timestamp instead:

function createVestingSchedule(
address beneficiary,
bytes32 category,
uint256 amount
) external onlyRole(ORCHESTRATOR_ROLE) whenNotPaused {
// ...
schedule.startTime = block.timestamp;
// ...
}
  1. Add strict time bounds if manual setting is required:

function createVestingSchedule(
address beneficiary,
bytes32 category,
uint256 amount,
uint256 startTime
) external onlyRole(ORCHESTRATOR_ROLE) whenNotPaused {
if (startTime < block.timestamp) revert InvalidStartTime();
if (startTime > block.timestamp + 30 days) revert StartTimeTooFar();
// ...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Appeal created

6ixty8ty Submitter
4 months ago
inallhonesty Lead Judge
4 months ago
6ixty8ty Submitter
4 months ago
inallhonesty Lead Judge
4 months ago
inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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