Skip to main content
Sigvex

Unsafe Downcasting Remediation

How to stop silent truncation when narrowing integer types by using checked casts.

Unsafe Downcasting Remediation

Overview

Related Detector: Unsafe Downcasting

Casting a wider integer to a narrower one — uint256 to uint128, uint64, uint32 — truncates the high bits with no revert, even under Solidity 0.8’s checked arithmetic (the overflow checks do not cover explicit casts). A value that exceeds the target width wraps to a small number, corrupting balances, timestamps, or packed storage. The remediation is a checked cast that reverts when the value does not fit.

Before (Vulnerable)

function record(uint256 amount) external {
    // If amount > type(uint128).max, the high bits are silently dropped.
    packedAmount = uint128(amount);
}

After (Fixed — checked cast)

// OpenZeppelin SafeCast reverts when the value does not fit the target type.
using SafeCast for uint256;

function record(uint256 amount) external {
    packedAmount = amount.toUint128();
}

If you cannot add a dependency, write the bound explicitly: require(amount <= type(uint128).max, "overflow"); packedAmount = uint128(amount);.

Common Mistakes

  • Believing Solidity 0.8’s built-in overflow checks cover downcasts — they do not; only arithmetic operators are checked.
  • Downcasting a signed/unsigned boundary (int256 to uint128) and losing the sign as well as the magnitude.
  • Packing several values into one slot with raw casts, so one oversized field silently corrupts its neighbours.

References