agents/skills/aptos/ability-analysis/SKILL.md
Trigger Pattern Always (Aptos Move) - foundational security check - Inject Into Breadth agents, depth agents
npx skillsauth add plamentsv/plamen ability-analysisInstall 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 (Aptos Move) --- foundational security check Inject Into: Breadth agents, depth agents
For every struct defined in the audited modules:
STEP PRIORITY: Steps 2 (Copy Ability Audit) and 6 (Ability Combination Analysis) are where HIGH/CRITICAL severity findings most commonly hide. Do NOT rush these steps. If constrained, skip conditional sections (7) before skipping 2 or 6.
Enumerate ALL structs defined in the audited modules:
| Struct | Module | Abilities | Represents Value? | Represents Obligation? | Is Resource? | Security Assessment | |--------|--------|-----------|-------------------|----------------------|-------------|---------------------| | {name} | {module} | copy, drop, store, key | YES/NO | YES/NO | YES/NO | {assessment} |
Classification guide:
For each struct: What abilities does it NEED vs what abilities does it HAVE? Excess abilities are the attack surface.
For each struct with the copy ability:
| Struct | Has copy? | Represents Value? | Duplication Exploitable? | Severity |
|--------|-------------|-------------------|-------------------------|----------|
| {name} | YES/NO | YES/NO | YES/NO --- {reason} | {H/M/L/N/A} |
CRITICAL: copy on a value-bearing type means the value can be duplicated at zero cost. This is the Move equivalent of a double-spend.
Check for each copy struct:
copy breaks that assumption.copy needed for legitimate operations? (e.g., snapshot reads, event emission) --- if not, it should be removed.MANDATORY GREP: Search all .move files for has copy and copy, in struct definitions. For each hit: (1) classify the struct, (2) if value-bearing, mark as FINDING.
For each copy struct identified as potentially dangerous:
1. Caller obtains instance I of struct S
2. Caller copies: I_copy = copy I
3. Caller uses I in function F1 (consumed/moved)
4. Caller uses I_copy in function F2 (consumed/moved)
5. Impact: {double-spend, double-claim, double-vote, obligation bypass}
Tag: [TRACE:copy S → use1 in F1 → use2 in F2 → impact: {X}]
For each struct with the drop ability:
| Struct | Has drop? | Represents Obligation? | Drop Bypasses Cleanup? | Severity |
|--------|-------------|----------------------|----------------------|----------|
| {name} | YES/NO | YES/NO | YES/NO --- {reason} | {H/M/L/N/A} |
CRITICAL: drop on an obligation-bearing struct means the obligation can be silently discarded. This is the Move equivalent of skipping a required finally-block.
Hot potato pattern check: The hot potato pattern relies on structs having NO drop ability, forcing the caller to pass them to a consuming function. If drop is present, the pattern is broken.
Check for each drop struct:
For each obligation struct:
1. Function F_create creates struct S (e.g., flash_loan returns receipt)
2. EXPECTED: Caller passes S to F_consume (e.g., repay(receipt))
3. ACTUAL (if drop): Caller drops S, F_consume never called
4. Impact: {funds not returned, lock not released, state inconsistent}
Tag: [TRACE:drop obligation S → F_consume skipped → impact: {X}]
For each struct with the store ability:
| Struct | Has store? | Can Escape Module? | Invariant Break If Escaped? | Severity |
|--------|-------------|-------------------|---------------------------|----------|
| {name} | YES/NO | YES --- via {mechanism} / NO | YES/NO --- {which invariant} | {H/M/L/N/A} |
Check for each store struct:
store allows the struct to be placed inside other structs, into Table/SmartTable, or moved to global storage via a wrapping resource. Can an attacker store this struct in their own resource, bypassing module-controlled access?store but without key: can they be wrapped in a user-defined key struct to achieve unauthorized global storage?&mut in the functions that operate on it), does escaping the module allow stale or orphaned references?For structs not intended to persist outside module control:
1. Module M creates struct S with `store` ability
2. Attacker wraps S in their own struct W (has key + store)
3. Attacker calls move_to<W>(@attacker, W { s: obtained_S })
4. S now persists at attacker's address outside M's control
5. Impact: {replay, hoarding, context-escape, stale state}
For each struct with the key ability:
| Struct | Has key? | Intended as Global Resource? | move_from Protected? | move_to Protected? | Severity |
|--------|-----------|----------------------------|---------------------|-------------------|----------|
| {name} | YES/NO | YES/NO | YES --- {by what} / NO | YES --- {by what} / NO | {H/M/L/N/A} |
Check for each key struct:
move_to for this resource? Is creation properly gated by access control (signer capability, admin checks)?move_from for this resource? Can an attacker remove a critical resource from an address?exists<S>(addr) checks? Can an attacker manipulate resource existence to bypass guards?For each resource that other functions depend on:
| Resource | Functions That Read It | Functions That Require exists<S> | Impact If Deleted | |----------|----------------------|--------------------------------|-------------------| | {name} | {list} | {list} | {abort, DoS, state corruption} |
Analyze dangerous ability combinations:
| Struct | Abilities | Combination Risk | Attack Vector | Severity | |--------|-----------|-----------------|---------------|----------| | {name} | copy + store | Replicate and persist duplicates in global storage | Infinite value creation via copy then store each copy | Critical | | {name} | drop + key | Abandon a top-level resource | Delete critical protocol state, DoS | High | | {name} | copy + drop | Infinite creation + no cleanup obligation | Value duplication with no consumption requirement | Critical (if value-bearing) | | {name} | copy + drop + store | All of the above combined | Maximum exploitation surface | Critical (if value-bearing) | | {name} | key + copy | Resource duplication at global level | Move resource to address, copy, move copy elsewhere | High |
MANDATORY: For every value-bearing or obligation-bearing struct, verify that NONE of these dangerous combinations are present. If present, classify as FINDING with severity based on the struct's role.
Safe combinations:
store alone on data structs (stored inside other resources, no standalone risk)copy + drop on purely informational structs (events, read-only parameters)key + store + drop on administrative resources with proper access controlFor every generic struct and generic function in the audited modules:
| Struct | Type Param | Constraint | Sufficient? | Unexpected Instantiation? |
|--------|-----------|-----------|-------------|--------------------------|
| Wrapper<T: store> | T | store | {analysis} | {can attacker use T = MaliciousType?} |
Check:
T: store + copy + drop when only store is needed) expand the attack surface.Pool<T: store> instantiated with a custom token type that has transfer hooks or non-standard behavior.phantom T): does the module correctly use them for type-level discrimination without relying on runtime properties of T?Check for mismatches between struct definition and function signatures:
struct Container<T: store> has key, store { item: T }
// POTENTIAL ISSUE: Function requires T: copy + store, but Container only requires T: store
// Can Container be created with a non-copy T, then this function fails?
public fun clone_item<T: copy + store>(c: &Container<T>): T { *&c.item }
Impact: If a module publishes a Container<NonCopyType>, the clone_item function aborts at runtime. Is this a DoS vector?
When this skill identifies an issue:
**ID**: [AB-N]
**Severity**: [based on struct role and exploitation impact]
**Step Execution**: check1,2,3,4,5,6,7 | X(reasons) | ?(uncertain)
**Rules Applied**: [R4:Y, R5:Y, R10:Y, R17:Y]
**Location**: module::struct_name (source_file.move:LineN)
**Title**: [Struct] has [ability] enabling [attack: duplication/obligation bypass/escape/deletion]
**Description**: [Trace the ability exploitation from struct definition to impact]
**Impact**: [What breaks: double-spend, obligation bypass, state corruption, DoS]
CRITICAL: You MUST report completion status for ALL sections. Steps 2 and 6 are highest priority.
| Section | Required | Completed? | Notes | |---------|----------|------------|-------| | 1. Struct Ability Inventory | YES | Y/X/? | Enumerate ALL structs | | 2. Copy Ability Audit | YES | Y/X/? | MANDATORY --- highest-severity source | | 2b. Copy-Then-Use Trace | IF copy on value type | Y/X(N/A)/? | | | 3. Drop Ability Audit | YES | Y/X/? | Hot potato pattern check | | 3b. Drop-Instead-of-Consume Trace | IF drop on obligation type | Y/X(N/A)/? | | | 4. Store Ability Audit | YES | Y/X/? | Module control escape | | 5. Key Ability Audit | YES | Y/X/? | Resource lifecycle | | 5b. Resource Deletion Impact | IF key resources found | Y/X(N/A)/? | | | 6. Ability Combination Analysis | YES | Y/X/? | MANDATORY --- dangerous combos | | 7. Generic Type Parameter Abilities | IF generics present | Y/X(N/A)/? | Constraint sufficiency |
After Section 2 (Copy Ability Audit):
TYPE_SAFETY.md Section 2 for type substitution amplificationAfter Section 3 (Drop Ability Audit):
After Section 6 (Ability Combination Analysis):
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