ability-analysis
Trigger Pattern Always (Aptos Move) - foundational security check - Inject Into Breadth…
Trigger Pattern Always (Aptos Move) - Move VM aborts on shift = bit width - Inject Into Breadth agents, depth-edge-case
$ npx -y skills add PlamenTSV/plamen --skill bit-shift-safety --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/bit-shift-safetyContext preview
The summary Claude sees to decide when to auto-load this skill.
Trigger Pattern Always (Aptos Move) - Move VM aborts on shift = bit width - Inject Into Breadth agents, depth-edge-case
name: "bit-shift-safety" description: "Trigger Pattern Always (Aptos Move) - Move VM aborts on shift = bit width - Inject Into Breadth agents, depth-edge-case"
> **Trigger Pattern**: Always (Aptos Move) --- Move VM aborts on shift >= bit width > **Inject Into**: Breadth agents, depth-edge-case
The Move VM performs a runtime check on every bit shift operation: if the shift amount is greater than or equal to the bit width of the operand type, the transaction aborts. This is not a silent wraparound --- it is a hard abort that reverts the entire transaction. Any user-controllable or computed shift amount that can reach the bit width threshold is a denial-of-service vector.
**MANDATORY GREP**: Search all `.move` files for `<<` and `>>` operators.
For each shift operation found:
| Location (file:line) | Operand Type | Bit Width | Shift Amount Source | User-Controllable? | Bounded? | |-----------------------|-------------|-----------|--------------------|--------------------|----------| | {file}:{line} | u8/u16/u32/u64/u128/u256 | 8/16/32/64/128/256 | constant / parameter / computed | YES/NO | YES/NO --- {how} |
**Classification of shift amount sources**:
For each shift operation where the shift amount is NOT a safe constant:
| Type | Bit Width | Max Safe Shift | Abort Condition | |------|-----------|---------------|-----------------| | u8 | 8 | 7 | shift >= 8 | | u16 | 16 | 15 | shift >= 16 | | u32 | 32 | 31 | shift >= 32 | | u64 | 64 | 63 | shift >= 64 | | u128 | 128 | 127 | shift >= 128 | | u256 | 256 | 255 | shift >= 256 |
For each non-constant shift:
| Location | Shift Amount Expression | Minimum Value | Maximum Value | Exceeds Bit Width? | Guard Present? | |----------|------------------------|---------------|---------------|-------------------|----------------| | {location} | {expression} | {min} | {max} | YES/NO | YES --- {assert/min/if} / NO |
**Verification method**: Trace the shift amount back to its origin. For each variable in the expression: 1. What is its declared type? (constrains range) 2. Is there an `assert!()` that bounds it before the shift? 3. Is there a `min()` or `if` guard? 4. Can the variable be set by an external caller (entry function parameter, stored value set by a public function)?
Tag: `[BOUNDARY:shift_amount={val} → abort at bit_width={W}]`
For shift amounts derived from arithmetic, perform boundary value analysis:
Pattern: `1 << (a - b)` where both `a` and `b` are unsigned integers.
| Location | Expression | Can `b > a`? | Underflow Result | Impact | |----------|-----------|-------------|-----------------|--------| | {location} | `1 << (decimals - 6)` | YES if decimals < 6 | Wraps to large u8/u64 → abort | DoS |
**Check**: Move unsigned subtraction aborts on underflow (no wraparound). So `a - b` where `b > a` aborts BEFORE the shift. This is a separate DoS vector (arithmetic underflow). Document both: 1. Underflow abort if `b > a` 2. Shift abort if `a - b >= bit_width`
Pattern: `value << (a + b)` or `value << (a * b)`
| Location | Expression | Can Sum/Product >= Bit Width? | Impact | |----------|-----------|------------------------------|--------| | {location} | {expression} | YES/NO --- {boundary values} | {DoS / safe} |
Even if the shift amount is safe, the RESULT of the shift may overflow the type:
| Location | Expression | Operand Max Value | Shift Amount | Result Exceeds Type Max? | Impact | |----------|-----------|-------------------|-------------|-------------------------|--------| | {location} | `amount << decimals` | {max} | {amount} | YES/NO | {silent truncation / abort} |
**Note**: Move does NOT abort on shift result overflow --- the result is silently truncated (high bits discarded). This is a correctness bug, not a DoS bug, but can cause incorrect calculations (e.g., `1u64 << 63` = 9223372036854775808, but `3u64 << 63` = 9223372036854775808 due to truncation).
Tag: `[BOUNDARY:shift_result=truncated at type_max]`
For each shift operation that can abort:
| Location | Function | Entry Point? | Who Calls This? | Abort Blocks What? | Severity | |----------|----------|-------------|----------------|--------------------|---------| | {location} | {function} | YES/NO | {callers} | {blocked operations} | {H/M/L} |
**Trace from the aborting shift outward**: 1. Which function contains the shift? 2. Is that function called by entry functions (user-facing)? 3. Is it called in a critical path (deposit, withdraw, claim, liquidation)? 4. Can an attacker provide input that triggers the abort? 5. Does the abort affect ONLY the attacker's transaction, or does it block other users?
**Severity guide**:
For shifts that can abort and are in shared/critical paths:
1. Attac
Autonomous Web3 security auditor for Claude Code and OpenAI Codex CLI. Orchestrates 18-100 AI agents across 40+ phases to produce audit reports with verified PoC exploits — for smart contracts and L1 node-client infrastructure.
Repo: PlamenTSV/plamen
Trigger Pattern Always (Aptos Move) - foundational security check - Inject Into Breadth…
Trigger Protocol has privileged roles (admin, operator, governance, resource account owner) -…
Trigger EXTERNAL_LIB flag detected (protocol uses third-party Move dependencies) - Used by…
Trigger Pattern MONETARY_PARAMETER flag (required) - Inject Into Breadth agents (merged via…
Trigger Pattern Any external module interaction detected in attack_surface.md - Inject Into…