Skip to main content
Sigvex

Incorrect Comparison Remediation

Choose the boundary-correct comparison operator so checks behave correctly at edge values.

Incorrect Comparison Remediation

Overview

A single wrong comparison operator can bypass access control, break accounting, or open an exploitable edge case. Off-by-one mistakes (> where >= was meant), comparisons across mismatched scales (wei against an ether-scale constant), and inverted boundary checks all produce correct results for most inputs and only fail at the boundary, which is exactly where attackers probe.

Related Detector: Incorrect Comparison

Before (Vulnerable)

function withdraw(uint256 amount) external {
    require(amount < balances[msg.sender], "Insufficient");  // Bug: should be <=
    balances[msg.sender] -= amount;
    payable(msg.sender).transfer(amount);
}

After (Fixed)

function withdraw(uint256 amount) external {
    require(amount <= balances[msg.sender], "Insufficient");
    balances[msg.sender] -= amount;
    payable(msg.sender).transfer(amount);
}

The fixed check allows withdrawing the exact full balance, which is the intended behavior, while still rejecting anything larger. Deciding deliberately whether each boundary value should pass or fail, then picking </<=/>/>= to match, is what makes the guard correct.

Alternative Mitigations

  • Write explicit unit tests for each boundary value (exactly equal, one below, one above) so an off-by-one fails the suite.
  • Normalize operands to the same scale before comparing; multiply or divide so both sides share units.
  • Where a maximum is involved, express it as a named constant so the intended inclusivity is documented.

Common Mistakes

  • Fixing one boundary check but leaving a paired check (such as a matching upper bound) with the old operator.
  • Comparing a wei value directly against a constant written in ether without scaling, so the check is off by 1e18.
  • Using strict inequality for a range that should be inclusive, silently excluding a valid value.

References