Skip to main content
Sigvex

Requirement Violations Exploit Generator

Sigvex exploit generator that validates requirement violation findings by classifying the specific check failure — incorrect comparison, missing validation, assert misuse, or arithmetic overflow — and documenting the exploit path.

Requirement Violations Exploit Generator

Overview

The requirement violations exploit generator validates findings from the requirement_violations, missing_require, assertion_failure, and related detectors by classifying the specific type of requirement violation from the finding description and generating documentation of the exploit path it creates. The generator handles four violation categories: incorrect comparisons, missing validations, assert misuse, and missing arithmetic checks.

Requirement violations are often subtle — a <= where < was intended, a missing zero-check on a division denominator, or an assert used where require was intended. Each creates a different class of exploitable behavior: arithmetic overflows silently wrap in Solidity 0.7.x and below, missing validations allow forbidden state transitions, and assert misuse causes permanent state corruption on expected failure conditions.

Note: Exploit generation in Sigvex is for vulnerability validation purposes only.

Attack Scenario

Incorrect comparison:

  1. A contract uses require(amount <= balance) instead of require(amount < balance).
  2. An attacker withdraws exactly balance — draining the contract to zero.
  3. Any subsequent users find the contract empty, including fees or reserves that should have been protected.

Missing validation:

  1. A function performs a division: result = total / shares.
  2. No check ensures shares > 0.
  3. When shares == 0 (e.g., during initial deployment or after all shares are burned), the division reverts unexpectedly.
  4. Alternatively, if the context is a ratio or rate calculation, a zero denominator allows misuse.

Assert misuse:

  1. A contract uses assert(condition) to validate user-supplied input.
  2. assert consumes all remaining gas when it fails (pre-EIP-3855 behavior) and does not refund.
  3. An attacker triggers the assert repeatedly, wasting enormous amounts of gas for legitimate users.
  4. Additionally, failed assert statements are caught differently in try/catch blocks than require failures.

Arithmetic overflow (missing check):

  1. A contract performs total += amount without SafeMath or Solidity 0.8.x overflow protection.
  2. An attacker passes a large amount that causes total to wrap around to a small value.
  3. The contract believes the total is small when it is actually astronomically large.
  4. Arbitrary amounts are credited or debited due to the wrapped value.

Exploit Mechanics

The generator classifies the violation type from the finding description:

Description contains Violation type Severity
comparison, equal, boundary incorrect_comparison Medium: off-by-one, draining
require, check, validation, zero missing_validation High: division by zero, invalid state
assert, invariant assert_misuse Low: gas waste, incorrect failure mode
overflow, underflow, arithmetic arithmetic_check_missing Critical: value manipulation

Evidence collected: violation type, finding location, severity classification. Estimated gas: 50,000.

// VULNERABLE: Incorrect comparison allows draining reserves
contract VulnerableVault {
    uint256 public balance;
    uint256 public reserve = 1000; // Protected minimum

    function withdraw(uint256 amount) external {
        require(amount <= balance); // Should be: amount <= balance - reserve
        balance -= amount;
        _transfer(msg.sender, amount);
    }
}

// VULNERABLE: Missing zero check
contract VulnerableDistributor {
    function distribute(uint256 total, uint256 shares) external {
        // shares could be 0 — division by zero!
        uint256 perShare = total / shares;
        _distribute(perShare);
    }
}

// VULNERABLE: Assert used for input validation
contract VulnerableToken {
    function transfer(address to, uint256 amount) external {
        assert(amount <= balances[msg.sender]); // Should be require()!
        // If assert fails: wastes all gas, no refund
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }
}

// VULNERABLE: No overflow protection (Solidity < 0.8.0)
contract VulnerableAccounting {
    uint256 public totalDeposits;

    function deposit(uint256 amount) external {
        totalDeposits += amount; // Can overflow in Solidity 0.7.x and below
        balances[msg.sender] += amount;
    }
}

// SECURE: All four violations corrected
contract SafeVault {
    uint256 public balance;
    uint256 public constant RESERVE = 1000;

    // Fix 1: Correct comparison boundary
    function withdraw(uint256 amount) external {
        require(amount > 0, "Amount must be positive");
        require(balance >= RESERVE + amount, "Insufficient balance above reserve");
        balance -= amount;
        _transfer(msg.sender, amount);
    }

    // Fix 2: Zero check before division
    function distribute(uint256 total, uint256 shares) external {
        require(shares > 0, "Shares must be positive");
        uint256 perShare = total / shares;
        _distribute(perShare);
    }

    // Fix 3: require() for user input, assert() for invariants only
    function transfer(address to, uint256 amount) external {
        require(amount <= balances[msg.sender], "Insufficient balance"); // User error
        balances[msg.sender] -= amount;
        balances[to] += amount;
        assert(balances[msg.sender] + balances[to] <= totalSupply); // True invariant
    }

    // Fix 4: Solidity 0.8.0+ built-in overflow protection (or SafeMath)
    // Solidity 0.8.0 throws on overflow automatically
    function deposit(uint256 amount) external {
        totalDeposits += amount; // Safe in 0.8.0+
        balances[msg.sender] += amount;
    }
}

Remediation

Each violation type requires a targeted fix:

Incorrect comparisons: Audit every comparison operator near balance, allowance, or limit checks. Use formal verification or fuzz testing to test boundary values (0, 1, max-1, max).

Missing validations: Add guard clauses at function entry for all user-controlled inputs:

require(amount > 0, "Amount must be positive");
require(denominator != 0, "Division by zero");
require(recipient != address(0), "Cannot send to zero address");

Assert misuse: Reserve assert() for mathematical invariants that should never be false given correct code. Use require() for all user input validation and business logic checks. If an assert can be triggered by user input, it is a bug.

Arithmetic overflows: Upgrade to Solidity 0.8.0+ for automatic overflow protection. For contracts that must use 0.7.x or below, apply OpenZeppelin’s SafeMath for all arithmetic on user-controlled values.

References