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()orrelease()functions,Misused block timestamps or assumptions aroundblock.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:
- A user is assigned a 1-year vesting schedule with linear release.
- The claim() function mistakenly transfers the full totalVested balance without checking the current vesting time.
- The user calls claim() immediately after allocation.
- 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
- SWC-124: Missing Time/Condition Check
- OpenZeppelin Token Vesting Contract
- Implementing Vesting in Crypto Projects โ Metalamp
โ 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.