agents/skills/sui/bit-shift-safety/SKILL.md
Trigger Pattern Always (Sui Move) -- Move VM aborts on shift = bit width - Inject Into Breadth agents, depth-edge-case
npx skillsauth add plamentsv/plamen bit-shift-safetyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Trigger Pattern: Always (Sui Move) -- Move VM aborts on shift >= bit width Inject Into: Breadth agents, depth-edge-case
For every bit shift operation in the protocol:
BACKGROUND: The Move VM (shared by Sui and Aptos) aborts the entire transaction if a bit shift operand equals or exceeds the bit width of the type. For u64, shifting by 64 or more aborts. For u128, shifting by 128 or more aborts. This is NOT a revert with an error code -- it is a VM abort that cannot be caught. On Sui, a PTB (Programmable Transaction Block) abort means ALL commands in the PTB fail, and shared objects that were locked for the transaction are released without state changes.
Enumerate ALL bit shift operations (<< and >>) across all modules:
| Module | Function | Line | Operation | Type | Bit Width | Shift Amount Source | Validated? |
|--------|----------|------|-----------|------|-----------|--------------------|-----------:|
| {mod} | {func} | {L} | << / >> | u8/u64/u128/u256 | 8/64/128/256 | {literal/parameter/computed} | YES/NO |
Grep pattern: Search all .move files for << and >> operators.
Type-to-width mapping:
| Type | Max Safe Shift |
|------|---------------|
| u8 | 7 |
| u64 | 63 |
| u128 | 127 |
| u256 | 255 |
For each shift operation, classify the shift amount source:
let x = value << 32; // Literal: always safe if < bit width
Check: Is the literal < bit width of the type? If yes -> SAFE. If no -> compilation may succeed but runtime aborts.
public fun shift_by(value: u64, amount: u8): u64 {
value << (amount as u8) // Parameter: caller controls shift amount
}
Check: Is the amount parameter validated before the shift? Common patterns:
assert!(amount < 64, E_SHIFT_OVERFLOW) -- explicit validationamount % 64 -- wrapping (changes semantics but prevents abort)let shift = calculate_precision(decimals); // Computed: depends on runtime state
let result = base << shift;
Check: Can the computation ever produce a value >= bit width? Trace the computation to its inputs. If any input is user-controlled or state-derived -> HIGH RISK.
For each unvalidated shift operation, assess the abort impact:
| Function | Called By | Shared Objects Locked? | PTB Context | Abort Impact | |----------|----------|----------------------|-------------|-------------| | {func} | {callers} | YES/NO | {typical PTB} | {impact} |
Sui-specific abort consequences:
&mut reference), those objects are temporarily unavailable during consensus. Repeated aborts can cause transient unavailability. This is NOT permanent locking -- Sui releases locks after the transaction fails.For each unvalidated shift in a public/entry function:
Scenario: Shift Abort Griefing
1. Attacker calls {FUNCTION} with shift amount = {BIT_WIDTH}
2. Move VM aborts the transaction
3. Impact on other users: {IMPACT}
- If function modifies shared state: other PTBs depending on that state must retry
- If function is part of a multi-step user flow: user loses gas + must restart
4. Attacker cost: gas for one failed transaction
5. Severity: {based on impact}
// VULNERABLE: decimals comes from token metadata, could be >= 64
let scale = 1u64 << decimals;
Fix pattern: assert!(decimals < 64, E_INVALID_DECIMALS) or use math::pow(10, decimals) instead.
// VULNERABLE if position is not bounds-checked
let field = (packed >> position) & mask;
Check: Is position derived from user input or configuration? If yes and no validation -> FINDING.
// Common in DeFi: fixed-point multiplication with shift
let result = (a * b) >> PRECISION_BITS;
Check: Is PRECISION_BITS a constant? If yes and < bit width -> SAFE. If computed -> trace source.
let mut i = 0;
while (i < n) {
value = value << 1; // Safe per iteration, but after 64 iterations value = 0 (not abort)
i = i + 1;
};
Note: Shifting by 1 repeatedly does NOT abort (shift amount is always 1). But the value overflows silently to 0 after bit-width iterations. Check if this silent overflow causes logic errors.
For each shift operation that IS validated, verify the validation is correct:
| Function | Validation | Correct? | Edge Case |
|----------|-----------|----------|-----------|
| {func} | assert!(n < 64) | YES | n=63 is max safe |
| {func} | assert!(n <= 64) | NO | n=64 aborts |
| {func} | n % 64 | SAFE but semantic change | shift by 0 when n=64 |
Common validation errors:
<= bit_width instead of < bit_widthu128 shift (allows 64-127 to abort)amount is u64 but shift operand must be u8 -- does the cast truncate?Trace shift amounts across function boundaries:
entry_function(user_input: u64)
-> helper_a(derived_value) // derived_value = user_input * 2
-> helper_b(shift_amount) // shift_amount = derived_value + offset
-> actual_shift: value << shift_amount // Is shift_amount < bit_width?
For each chain: Can ANY combination of valid inputs to the entry function produce a shift amount >= bit width at the actual shift site? Document the full trace.
**ID**: [BS-N]
**Severity**: [HIGH if public function, MEDIUM if restricted caller, LOW if constant shift]
**Step Execution**: check1,2,3,4,5,6 | X(reasons) | ?(uncertain)
**Rules Applied**: [R4:Y, R10:Y, ...]
**Depth Evidence**: [BOUNDARY:shift=bit_width], [TRACE:user_input->shift_amount->abort]
**Location**: module::function:LineN
**Title**: Unvalidated bit shift in [function] causes VM abort on [condition]
**Description**: [Specific shift operation, source of shift amount, why it can reach bit width]
**Impact**: [Transaction abort, shared object locking, griefing potential, gas waste]
CRITICAL: You MUST report completion status for ALL sections. Findings with incomplete sections will be flagged for depth review.
| Section | Required | Completed? | Notes |
|---------|----------|------------|-------|
| 1. Shift Operation Inventory | YES | Y/X/? | Grep all .move files |
| 2. Shift Amount Source Classification | YES | Y/X/? | For each shift |
| 3. Abort Impact Analysis | IF unvalidated shifts found | Y/X(N/A)/? | |
| 3a. Griefing Scenario Modeling | IF unvalidated in public fn | Y/X(N/A)/? | |
| 4. Common Vulnerable Patterns | YES | Y/X/? | Check all 4 sub-patterns |
| 5. Validation Pattern Verification | IF validated shifts exist | Y/X(N/A)/? | Off-by-one check |
| 6. Cross-Function Shift Propagation | IF shift amount crosses functions | Y/X(N/A)/? | |
After Section 1 (Shift Inventory):
After Section 3 (Abort Impact):
After Section 6 (Cross-Function Propagation):
[BOUNDARY:shift={bit_width}], [TRACE:input_path->abort_site]development
Prepare Solidity projects for a security audit — test coverage, test quality, NatSpec docs, code hygiene, dependency health, best-practice enforcement, deployment readiness, and project documentation checks. Generates a scored Audit Readiness Report and optionally runs static analysis. Trigger on: "prepare for audit", "audit readiness", "pre-audit check", "audit prep", "NatSpec check", or any request to review a Solidity codebase before a security review.
development
Launch the Plamen deterministic Web3 security audit pipeline
development
Run the Plamen smart-contract audit wizard in Codex
testing
Launch the Plamen deterministic L1 infrastructure audit pipeline