Company Simulator

First Flight #51
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

Timestamp manipulation enables premature withdrawals and bypasses lockup logic

Root + Impact

Description

  • Normal behavior:

    The contract uses timestamps to enforce a lockup period on investor withdrawals and other time-based actions (e.g., LOCKUP_PERIOD, share unlocks, or cooldowns).

    Investors should only be able to withdraw after the set period elapses.

    Explain the specific issue or problem in one or more sentences

  • Specific issue:

  • The code relies directly on block.timestamp for time comparison and assumes it is always accurate.

  • However, in Ethereum, miners can manipulate block.timestamp within ~15 seconds of the actual time.

  • When combined with short lock periods or sequential time checks (like “one week later”), this manipulation can enable:

1.Premature withdrawals,

2.Early unlocking of restricted actions,

3.Bypass of intended temporal security boundaries.

// Root cause in the codebase with @> marks to highlight the relevant section
@external
def withdraw_shares():
assert msg.sender in self.shares, "Not an investor!!!"
@> assert block.timestamp >= self.LOCKUP_PERIOD, "Shares still locked!!!"
...

Risk

Likelihood:

  • Medium — Exploitable by miners or validators with block production control, or in private testnets where timestamp drift is more flexible.

  • Occurs naturally in short lockup or repeated “cooldown” systems where ±15 seconds makes a difference.

Impact:

  • High — Investors (or miners cooperating with them) can withdraw or redeem shares early, breaking vesting or incentive mechanisms.

  • Time-sensitive financial logic (e.g., bond maturity, auction settlement, or bonus timing) can be manipulated, reducing fairness and potentially leading to profit loss or reputation damage.

Proof of Concept

Explanation:

By slightly advancing the block’s timestamp, a miner or manipulated environment can pass the time check even before the lock period ends, thus allowing premature withdrawal.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
PoC: Demonstrates early withdrawal by manipulating block.timestamp.
This simulates a miner or local test environment advancing timestamp slightly.
*/
interface IVuln {
function withdraw_shares() external;
function fund_cyfrin(uint256 action) external payable;
}
contract TimestampAttack {
IVuln public target;
constructor(address _target) {
target = IVuln(_target);
}
function simulateAttack() external payable {
// Fund to become an investor
target.fund_cyfrin{value: msg.value}(1);
// Normally must wait LOCKUP_PERIOD, but miner sets timestamp +1s ahead
// and attacker can now withdraw early
target.withdraw_shares();
}
}

Recommended Mitigation

Explanation (brief)

Avoid relying solely on block.timestamp for strict time-based constraints.

Use block numbers or add a minimum safety buffer to reduce manipulability.

In sensitive financial contexts, external verifiers or off-chain oracles can validate elapsed time more reliably.

- remove this code
+ add this code
@@
- assert block.timestamp >= self.LOCKUP_PERIOD, "Shares still locked!!!"
+ # Add small safety window and record per-user unlock time
+ unlock_time: uint256 = self.investor_unlock_time[msg.sender]
+ assert unlock_time > 0, "No recorded unlock time"
+ # Enforce a buffer to mitigate small timestamp manipulation
+ assert block.timestamp >= unlock_time + 15, "Lockup period not safely elapsed"
Updates

Lead Judging Commences

0xshaedyw Lead Judge
5 days ago
0xshaedyw Lead Judge 4 days ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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