Skip to content
Security
Skill

/type-safety

Trigger Pattern Always (Aptos Move) - generic type exploitation - Inject Into Breadth agents, depth-state-trace

From plugin
plamen
276160 skills12 agents4 commands
Install
$ npx -y skills add PlamenTSV/plamen --skill type-safety --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/type-safety

Context preview

The summary Claude sees to decide when to auto-load this skill.

Trigger Pattern Always (Aptos Move) - generic type exploitation - Inject Into Breadth agents, depth-state-trace

SKILL.md

type-safety.SKILL.md
name: "type-safety"
description: "Trigger Pattern Always (Aptos Move) - generic type exploitation - Inject Into Breadth agents, depth-state-trace"

TYPE_SAFETY Skill

> **Trigger Pattern**: Always (Aptos Move) --- generic type exploitation > **Inject Into**: Breadth agents, depth-state-trace

Move's type system is its primary security mechanism. Generic type parameters allow modules to be polymorphic, but incorrect or insufficient type constraints enable attackers to substitute unexpected types, bypass access control, confuse token types, or exploit phantom type assumptions. This skill audits every generic interface for type safety violations.

**STEP PRIORITY**: Steps 2 (Type Parameter Substitution) and 5 (Coin/FungibleAsset Type Confusion) are where HIGH/CRITICAL severity findings most commonly hide. Do NOT rush these steps. If constrained, skip conditional sections (3, 4) before skipping 2 or 5.

1. Generic Function Inventory

Enumerate ALL public, public(friend), and entry functions with generic type parameters:

| Function | Module | Type Params | Constraints | Visibility | Entry? | Who Can Call | |----------|--------|-------------|-------------|-----------|--------|-------------| | `withdraw<T>` | vault | T | `key` | public | YES | Any signer | | `swap<X, Y>` | dex | X, Y | `store` | public | YES | Any signer |

**MANDATORY GREP**: Search all `.move` files for `fun .*<` to find every generic function. Include internal (`fun`), `public(friend) fun`, `public fun`, and `public entry fun`.

For each generic function, additionally note:

  • Does the function create, destroy, or transfer instances of the generic type?
  • Does the function make assumptions about the generic type beyond its constraints? (e.g., assuming T is a coin type when the constraint is only `store`)
  • Is the generic parameter used as a phantom/tag or does the function operate on actual instances of T?

2. Type Parameter Substitution Analysis

For each generic function identified in Step 1, analyze what happens when an attacker substitutes an unexpected type:

2a. Substitution Attack Table

| Function | Type Param | Expected Type | Attacker Substitutes | Guard Against Wrong Type? | Impact | |----------|-----------|---------------|---------------------|--------------------------|--------| | `withdraw<T>(store)` | T | RealCoin | FakeCoin (attacker-defined) | YES --- {mechanism} / NO | {impact} |

**Attack methodology per function**:

1. **Identify expected type**: What type does the protocol developer intend callers to use? This is often documented but NOT enforced at the type level. 2. **Check enforcement**: Is there an on-chain mechanism that restricts T to the expected type? Common mechanisms:

  • Registered type list (module stores `TypeInfo` and checks against it)
  • Type witness parameter (function also requires `&TypeWitness<T>`)
  • Module-level resource check (`assert!(exists<Pool<T>>(@protocol), E_INVALID_TYPE)`)
  • `coin::is_coin_initialized<T>()` check
  • Signer-of-defining-module pattern (only the module that defines T can call)

3. **If NO enforcement**: What happens if attacker creates `module attacker::fake { struct FakeCoin has store {} }` and calls `withdraw<FakeCoin>()`?

2b. Cross-Pool / Cross-Market Type Confusion

For protocols with pools, markets, or vaults parameterized by type:

| Pool/Market | Type Parameter | Can Attacker Create Pool With Arbitrary Type? | Impact If Confusion | |-------------|---------------|----------------------------------------------|---------------------| | `Pool<T>` | T | YES --- anyone can call `create_pool<T>()` / NO | {drain, mispricing, accounting error} |

**Check**: If Pool<RealCoin> and Pool<FakeCoin> exist, can operations on one affect the other? Common issues:

  • Shared global state accessed by both pools
  • Price oracle shared between pools (attacker manipulates FakeCoin price, affects RealCoin pool)
  • Reward distribution computed across all pools regardless of type

Tag: `[TRACE:substitute T=FakeCoin → {function} → {bypass/confusion} → impact: {X}]`

3. Phantom Type Audit

For structs with phantom type parameters (`phantom T`):

3a. Phantom Type Inventory

| Struct | Phantom Param | Purpose | Runtime Impact of T | Can T Be Forged? | |--------|--------------|---------|--------------------|--------------------| | `Pool<phantom CoinType>` | CoinType | Type-tag discrimination | None (phantom) | {analysis} |

**Phantom type rules in Move**:

  • Phantom type parameters do NOT affect runtime representation --- two structs with different phantom types have the same memory layout.
  • Phantom types are used for type-level tagging: `Pool<USDC>` vs `Pool<WETH>` are different types at the Move level but identical at the bytecode level.
  • The compiler enforces that phantom types are not used in non-phantom positions.

**Check for each phantom type**: 1. Is the phantom parameter used ONLY for type discrimination (correct use)? 2. Does any function extract or operate on the phantom type at runtime? (should be impossible by compiler, but verify no workarounds) 3. Can an attacker create a struct with a phantom type that aliases an existing legitimate phantom type? (e.g., creating `Pool<AttackerCoin>` that interacts with `Pool<USDC>` state) 4. Are phantom type parameters properly propagated through nested generics? (`Wrapper<phantom T>` containing `Inner<T>` --- is T phantom in Inner too?)

3b. Phantom Type Bypass Patterns

| Pattern | Risk | Check | |---------|------|-------| | Phantom used for access control | Medium | Can attacker define their own type to bypass access gate? | | Phantom used for pool isolation | High | Does pool isolation rely solely on phantom type discrimination? | | Phantom type in event emission | Low | Can attacker emit events with spoofed phantom types for off-chain confusion? |

4. Type Witness Pattern

For functions that accept type witnesses:

4a. Witness Inventory

| Witness Struct | Creating Module | Who Can

Read more
Ships withplamen

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.

Get the whole plugin