Skip to content

Vesting Shortcut Exploits

id: LS23H
title: Vesting Shortcut Exploits 
baseSeverity: H
category: tokenomics
language: solidity
blockchain: [ethereum]
impact: Users may bypass vesting schedules and claim unearned tokens
status: draft
complexity: medium
attack_vector: internal
mitigation_difficulty: medium
versions: [">=0.6.0", "<latest"]
cwe: CWE-863
swc: SWC-124

๐Ÿ“ Description

  • Vesting shortcut exploits occur when users are able to bypass time-locked or vesting conditions due to flawed logic in the vesting or claiming contract.
  • This may happen due to: Unchecked edge conditions in claim() or release() functions,Misused block timestamps or assumptions around block.number.
  • Mistakes in the linear vesting formula or cliff handling.
  • As a result, malicious or impatient users can claim more tokens than earned, drain the vesting pool prematurely, or invalidate fair distribution mechanisms.

๐Ÿšจ Vulnerable Code

function claim() public {
    uint256 amount = totalVested[msg.sender]; // โŒ does not factor in vesting schedule
    require(amount > 0, "Nothing to claim");
    totalVested[msg.sender] = 0;
    token.transfer(msg.sender, amount);
}

๐Ÿงช Exploit Scenario

Step-by-step bypass:

  1. A user is assigned a 1-year vesting schedule with linear release.
  2. The claim() function mistakenly transfers the full totalVested balance without checking the current vesting time.
  3. The user calls claim() immediately after allocation.
  4. They receive 100% of their tokens, bypassing the vesting cliff and violating tokenomics.

Assumptions:

  • Cliff ignored: Cliff date check missing or set in the past.
  • Multiplying by block.timestamp instead of using time deltas.
  • Floating-point arithmetic errors causing overflows in earned().

โœ… Fixed Code

function claim() external {
    uint256 releasable = vestedAmount(msg.sender) - claimed[msg.sender];
    require(releasable > 0, "Nothing vested yet");

    claimed[msg.sender] += releasable;
    token.transfer(msg.sender, releasable);
}

function vestedAmount(address user) public view returns (uint256) {
    if (block.timestamp < startTime[user] + cliff) return 0;
    uint256 elapsed = block.timestamp - startTime[user];
    if (elapsed >= duration[user]) return totalVested[user];

    return (totalVested[user] * elapsed) / duration[user];
}

๐Ÿงญ Contextual Severity

- context: "Default"
  severity: H
  reasoning: "Unrestricted early claims result in vesting collapse and potential tokenomics damage."
- context: "Manually Managed Private Vesting"
  severity: M
  reasoning: "Smaller scope, more monitoring, and trusted parties reduce risk."
- context: "DAO-controlled Multisig Vesting Contracts"
  severity: L
  reasoning: "Upgrades and revocations are possible under collective oversight."

๐Ÿ›ก๏ธ Prevention

Primary Defenses

  • Use elapsed time checks to compute release amounts (now - startTime).
  • Enforce cliff logic before any claim is allowed.
  • Track claimed amount separately to prevent reclaims.

Additional Safeguards

  • Use battle-tested vesting libraries (e.g., OpenZeppelin TokenVesting.sol).
  • Avoid floating-point math or division truncation bugs.
  • Test vesting schedules over edge conditions (cliff, near expiry, before start).

Detection Methods

  • Slither: vesting-bypass, missing-cliff-check, timestamp-math-bug detectors.
  • Unit tests for multiple time checkpoints and boundary conditions.
  • Manual audit of claim() and vestedAmount() for time logic correctness.

๐Ÿ•ฐ๏ธ Historical Exploits

  • Name: Hedgey Finance Vesting Exploit
  • Date: March 2024
  • Loss: Undisclosed
  • Post-mortem: Link to post-mortem

๐Ÿ“š Further Reading


โœ… Vulnerability Report

id: LS23H
title: Vesting Shortcut Exploits 
severity: H
score:
impact: 5         
exploitability: 3 
reachability: 4  
complexity: 2     
detectability: 5 
finalScore: 4.1

๐Ÿ“„ Justifications & Analysis

  • Impact: Critical in token launches โ€” can ruin distribution or allow insider abuse.
  • Exploitability: Moderate โ€” no external access needed if claim is public.
  • Reachability: Often found in early-stage or custom-built vesting schedules.
  • Complexity: Easy to fix once identified, but often overlooked.
  • Detectability: High โ€” test and audit coverage should always include time-based logic.