Skip to main content
Sigvex

Timestamp Dependence

Detects reliance on block.timestamp for time-sensitive logic where validator manipulation of the timestamp by up to ~15 seconds can influence outcomes.

Timestamp Dependence

Overview

Remediation Guide: How to Fix Timestamp Dependence

The timestamp dependence detector identifies smart contract logic that relies on block.timestamp (EVM opcode TIMESTAMP) for outcomes where a validator’s ability to adjust the timestamp by approximately 15 seconds creates an exploitable window. Validators can include a block with a timestamp anywhere in the range [parent_timestamp + 1, now + 15s], giving them slight but potentially profitable control over time-sensitive contract logic.

Sigvex scans for TIMESTAMP opcode usage and traces the value through data-flow to determine whether it influences: random seed generation (covered by weak-randomness), deadline comparisons, time-lock releases, interest accrual cutoffs, or auction end conditions. The detector is specifically concerned with applications where a 15-second manipulation window has financial impact.

Why This Is an Issue

While block.timestamp is generally reliable for long-duration timekeeping (days, weeks), it is unsuitable for sub-minute precision. The 15-second manipulation window is enough to:

  • Prevent an auction from ending at the stated time
  • Cause a staking reward to accrue slightly more or less than intended
  • Allow a validator who controls a time-locked function to unlock it one block early
  • Bias a random outcome that depends on precise timing

Pre-Merge, miners had more flexibility. Post-Merge (Ethereum PoS), validators have a smaller manipulation window but it is not zero.

How to Resolve

// Before: Vulnerable — vulnerable to 15-second validator manipulation
function endAuction() external {
    require(block.timestamp >= auctionEnd, "Auction still running");
    // Finalize auction...
}

// For many use cases, block.timestamp is acceptable — use block.number for precision
// After: Use block number for time-critical logic with fine granularity
uint256 public endBlock;

function endAuction() external {
    require(block.number >= endBlock, "Auction still running");
    // block.number cannot be manipulated by validators in PoS
}

For applications that genuinely need wall-clock time with higher precision:

// Use an aggregated oracle for off-chain time when precision matters
import "@audited/interfaces/AggregatorV3Interface.sol";

// For most deadline/cooldown cases, block.timestamp is fine if the window is > 30s
// Document the acceptable tolerance explicitly
uint256 public constant TIMESTAMP_TOLERANCE = 15 seconds;
uint256 public deadline;

function isExpired() public view returns (bool) {
    // Allow 15s tolerance — make this explicit in documentation
    return block.timestamp > deadline + TIMESTAMP_TOLERANCE;
}

Examples

Vulnerable Code

// Seed generation using timestamp — covered also by weak-randomness
contract VulnerableAuction {
    uint256 public endTime;
    address public highestBidder;

    // Validator can manipulate to prevent end at exactly the right moment
    function finalizeAuction() external {
        require(block.timestamp >= endTime, "Not ended");
        // Validator with 15-second window can decide whether to include this
        // — beneficial if they want to extend bidding
        _transferToBidder(highestBidder);
    }
}

Fixed Code

contract SecureAuction {
    uint256 public endBlock;  // Use block number instead

    constructor(uint256 durationBlocks) {
        endBlock = block.number + durationBlocks;
    }

    function finalizeAuction() external {
        require(block.number >= endBlock, "Not ended");
        _transferToBidder(highestBidder);
    }
}

Sample Sigvex Output

{
  "detector_id": "timestamp",
  "severity": "medium",
  "confidence": 0.72,
  "description": "Function finalizeAuction() uses block.timestamp as the sole condition for a financial operation. Validators can manipulate this by up to 15 seconds.",
  "location": { "function": "finalizeAuction()", "offset": 44 }
}

Detection Methodology

  1. TIMESTAMP opcode detection: Identifies all uses of the TIMESTAMP opcode.
  2. Financial impact assessment: Traces the timestamp value to determine whether it influences: financial transfers, token minting, interest calculations, or access control with time-dependent logic.
  3. Window size estimation: Attempts to determine the sensitivity of the comparison (e.g., >= deadline with a deadline in the past by only seconds is more critical than a comparison with a 7-day window).
  4. Non-critical usage recognition: Timestamp used for event emission, logging, or informational display is not flagged.

Limitations

False positives:

  • block.timestamp is perfectly acceptable for cooldown periods longer than 30 seconds, staking reward periods, and protocol-level timeouts. These may still be flagged at lower confidence.
  • Timestamps used only for event parameters or off-chain indexing are sometimes caught.

False negatives:

  • Indirect timestamp usage (stored in storage, then read later in a different function) may be missed without cross-function analysis.

References