Sign Extension Overflow
Detects unsafe sign extension in type conversions between signed and unsigned integers, where negative values become large positive numbers.
Sign Extension Overflow
Overview
The sign extension overflow detector identifies unsafe type conversions where signed integers (int8, int16, etc.) are cast to unsigned integers (uint256) without checking for negative values. In the EVM, the SIGNEXTEND opcode fills the upper bits of a negative number with 1s, converting a small negative value into a very large uint256. This can bypass amount checks, corrupt calculations, or enable fund theft.
Why This Is an Issue
When int8(-1) is cast to uint256, the result is 2^256 - 1 (the maximum uint256 value). If this value is used in a transfer amount, balance comparison, or array index, the consequences are severe:
- A negative fee becomes a massive positive credit
- A negative price delta becomes an enormous positive value
- Signed offsets converted to unsigned lengths cause memory corruption
SWC-148 documents this class of vulnerability. Historical exploits include price oracle manipulations where negative price changes were misinterpreted as large positive values.
How to Resolve
// Before: Direct cast of potentially negative value
function applyDelta(int256 delta) external {
uint256 amount = uint256(delta); // If delta < 0, amount = 2^256 + delta
balances[msg.sender] += amount;
}
// After: Check sign before conversion
function applyDelta(int256 delta) external {
require(delta >= 0, "Negative delta");
uint256 amount = uint256(delta);
balances[msg.sender] += amount;
}
Examples
Vulnerable Code
contract VulnerablePriceOracle {
function updatePrice(int256 priceChange) external {
// Negative change wraps to massive uint256
uint256 newPrice = basePrice + uint256(priceChange);
currentPrice = newPrice; // Price set to near-max uint256
}
}
Fixed Code
contract SafePriceOracle {
function updatePrice(int256 priceChange) external {
if (priceChange >= 0) {
currentPrice = basePrice + uint256(priceChange);
} else {
uint256 decrease = uint256(-priceChange);
require(basePrice >= decrease, "Price underflow");
currentPrice = basePrice - decrease;
}
}
}
Sample Sigvex Output
{
"detector_id": "sign-extension-overflow",
"severity": "high",
"confidence": 0.88,
"description": "SIGNEXTEND at offset 0x4c converts int256 parameter to uint256 without sign check. A negative value produces a near-maximum uint256, enabling balance inflation.",
"location": { "function": "updatePrice(int256)", "offset": 76 }
}
Detection Methodology
- SIGNEXTEND detection: Identifies
SIGNEXTENDopcodes in the bytecode that indicate signed-to-unsigned conversions. - Source tracking: Traces the signed value back to its origin (calldata, storage, external call return).
- Guard analysis: Checks for preceding comparison operations that validate the sign (SLESS, SGT against zero).
- Usage analysis: Evaluates how the converted value is used — arithmetic, comparison, transfer amount, or array index.
Limitations
- Cannot distinguish between intentional two’s-complement arithmetic (where wrapping is expected) and accidental sign extension.
- Solidity 0.8+ prevents some implicit conversions but explicit casts (
uint256(signedValue)) are still permitted without checks. - Assembly blocks that manually perform SIGNEXTEND are analyzed, but complex bitwise operations may be missed.
Related Detectors
- Integer Overflow — general integer overflow/underflow detection
- Unsafe Downcasting — unsafe type narrowing conversions
- Incorrect Comparison — wrong comparison operators