Arbitrary Jump
Detects JUMP or JUMPI instructions where the destination is derived from user input, enabling control-flow hijacking.
Arbitrary Jump
Overview
Remediation Guide: How to Fix Arbitrary Jump
The arbitrary jump detector identifies JUMP or JUMPI instructions where the destination address on the stack is derived from user-controlled input. In the EVM, JUMP transfers execution to a JUMPDEST instruction at the specified offset. If an attacker controls this offset, they can redirect execution to any JUMPDEST in the contract, bypassing access control checks, re-entering critical sections, or reaching code paths that were not intended to be directly accessible.
Sigvex traces the jump destination operand through the data-flow graph to determine whether it originates from calldata.
Why This Is an Issue
While the EVM restricts jump targets to valid JUMPDEST instructions (not arbitrary bytecode offsets), a contract with multiple JUMPDEST markers still provides an attacker with several potential landing points. An attacker who controls the jump destination can skip over require checks, bypass modifier logic, or jump directly to fund-transfer code that was meant to be guarded.
This vulnerability is less common in modern Solidity (which generates computed jumps only for internal dispatch) but can appear in hand-written assembly, Yul contracts, or contracts generated by non-standard compilers.
How to Resolve
// Before: Vulnerable — user-controlled jump destination
function dispatch(uint256 dest) external {
assembly {
jump(dest) // Attacker chooses execution target
}
}
// After: Fixed — use a switch statement with known destinations
function dispatch(uint256 action) external {
if (action == 1) { _handleDeposit(); }
else if (action == 2) { _handleWithdraw(); }
else { revert("Unknown action"); }
}
Examples
Vulnerable Code
contract VulnerableDispatch {
// User-controlled jump target
function execute(uint256 jumpTarget) external payable {
assembly {
jump(jumpTarget) // Control-flow hijacking
}
}
}
Fixed Code
contract SafeDispatch {
function execute(uint256 action) external payable {
if (action == 0) {
_deposit();
} else if (action == 1) {
_withdraw();
} else {
revert("Invalid action");
}
}
function _deposit() internal { /* ... */ }
function _withdraw() internal { /* ... */ }
}
Sample Sigvex Output
{
"detector_id": "arbitrary-jump",
"severity": "critical",
"confidence": 0.85,
"description": "JUMP at offset 0x3f uses a destination from calldata. An attacker can redirect execution to any JUMPDEST in the contract, bypassing access control.",
"location": { "function": "execute(uint256)", "offset": 63 }
}
Detection Methodology
- JUMP/JUMPI identification: Locates all
JUMPandJUMPIinstructions in the bytecode. - Destination taint analysis: Traces the destination operand backward to determine if it originates from user input (
CALLDATALOAD). - Compiler pattern exclusion: Excludes the standard Solidity function selector dispatch pattern (which uses computed jumps from
CALLDATALOADbut only to compiler-generatedJUMPDESTlocations in the dispatcher). - JUMPDEST enumeration: Counts available
JUMPDESTmarkers to assess the attack surface — more destinations mean higher risk.
Limitations
False positives:
- Solidity’s internal function dispatch mechanism uses computed jumps from calldata, but these are restricted to the function selector table. The detector excludes this pattern, but edge cases may trigger false positives.
False negatives:
- Jump destinations computed through complex arithmetic may not be traced to user input.
- Contracts using the
JUMPIconditional variant with a user-controlled condition (but compiler-controlled destination) are a different vulnerability class.
Related Detectors
- Arbitrary Storage Write — detects user-controlled storage slot writes
- Access Control — detects missing authorization checks