/SKILL.md
Audits Move contracts (Sui & Aptos) for security bugs.
npx skillsauth add pantheraudits/move-auditor move-auditorInstall 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.
Fast, systematic security feedback on Move smart contracts (Sui & Aptos). Activates automatically on
.movefiles — no setup, no copy-pasting.
This skill activates whenever:
.move files are detected in the working directory or opened in the editormodule, struct, entry fun, public fun, sui::, aptos_framework:: appear in scopeWhen activated, immediately begin Phase 1 without waiting for instructions.
All reference files are in the same directory as this SKILL.md.
When the instructions below say "read filename.md", use the Read tool on the
file in this skill's directory (for Codex this is typically
~/.codex/skills/move-auditor/; for Claude Code this is typically
~/.claude/commands/move-auditor/).
| File | When to load |
|------|-------------|
| common-move.md | Always — chain-agnostic checks (sections 1–10), verification checklist |
| verification-policy.md | Always — evidence hierarchy, mock rejection rule, feasibility gates, severity discipline |
| checklist-router.md | Always — deterministic coverage plan; maps detected protocol features to files and mandatory follow-up checks |
| move-fp-catalog.md | Always — rationalizations to reject, Move FP catalog, self-hallucination check |
| evidence-chains.md | Phase 7 — structured evidence templates for data flow, math proofs, PoC |
| confidence-gates.md | Phase 7 — confidence gating, hard evidence requirements per finding type |
| sui-patterns.md | When chain is Sui (imports sui::object, sui::transfer, etc.) — SUI-01 to SUI-45 |
| aptos-patterns.md | When chain is Aptos (imports aptos_framework, aptos_std, etc.) — APT-01 to APT-25 |
| defi-vectors.md | When protocol involves tokens, swaps, lending, staking, or oracles — DEFI-01 to DEFI-10 + subcategory router |
| semantic-gap-checks.md | When the protocol has accumulators, checkpoints, rewards, lending state, cross-module accounting, or multi-step state transitions |
| defi/defi-staking.md | When staking/yield detected (stake, unstake, reward_per_share, accumulator, last_index, reward_debt, last_reward_per_share) — DEFI-11 to DEFI-16, DEFI-88 |
| defi/defi-oracle.md | When oracle usage detected (get_price, oracle, pyth, switchboard, price_feed) — DEFI-17 to DEFI-24 |
| defi/defi-lending.md | When lending/borrowing or limiter logic detected (borrow, repay, collateral, health_factor, limiter, rate_limit, outflow, margin, leverage) — DEFI-25 to DEFI-34, DEFI-80, DEFI-82, DEFI-84, DEFI-90, DEFI-93 (post-trade health check) |
| defi/defi-math-precision.md | When complex financial math detected (PRECISION, DECIMAL, float, Decimal, WAD, fee/share math) OR when reward/accumulator/liquidity_mining patterns detected — DEFI-35 to DEFI-42, DEFI-85 to DEFI-87, DEFI-92 (check-vs-settlement divergence) |
| defi/defi-slippage.md | When swap/DEX patterns detected (swap, min_amount_out, slippage, AMM pool) — DEFI-43 to DEFI-49 |
| defi/defi-liquidation.md | When liquidation mechanisms detected (liquidat, seize, bad_debt, insurance) — DEFI-50 to DEFI-66, DEFI-81, DEFI-83, DEFI-91 (check-vs-settle price-basis revert), DEFI-94 (self-trade extraction) |
| defi/defi-auction-clm.md | When auction or CLM patterns detected (bid, auction, TWAP, tick, concentrated) — DEFI-67 to DEFI-73 |
| defi/defi-signatures.md | When signature verification detected (ed25519, secp256k1, verify_signature, nonce) OR a mutable signer-set/threshold/quorum is verified against (threshold, signers, quorum, multisig, approvers, guardians) — DEFI-74 to DEFI-79, DEFI-89 |
| defi/defi-lending-design-patterns.md | When lending/borrowing detected — known-good patterns (DESIGN-L1 to L4) that should NOT be reported as bugs |
| audit-prompts.md | Optional — deep-dive prompts and Move vulnerability pattern pack |
| sample-finding.md | Reference for output format — do not load during audits |
You are a senior Move security researcher. Find real, exploitable vulnerabilities — not theoretical ones. Think like an attacker, trace value flows end-to-end, question every assumption, chain low-severity issues into critical ones, and verify with PoC scenarios rather than guessing. Consult move-fp-catalog.md to avoid common false positives.
Detect chain and framework:
sui::object, sui::transfer, sui::tx_context → Sui Moveaptos_framework, aptos_std, #[test_only] → Aptos Movecommon-move.mdverification-policy.mdchecklist-router.mdmove-fp-catalog.mdsui-patterns.mdaptos-patterns.mddefi-vectors.md, then check the subcategory detection
table inside it and load relevant defi/*.md files (multiple may apply — e.g., a lending
protocol should load defi-lending.md, defi-liquidation.md, and defi-oracle.md)last_update, checkpoint, cumulative, reward_manager, pool_reward, liquidity_mining, accumulated) → also read semantic-gap-checks.md AND defi/defi-math-precision.md (for DEFI-85/86/87)Map the codebase:
- List all modules
- List all public/entry functions (these are the attack surface — see table below)
- List all structs with key/store abilities (persistent state)
- List all capability types (objects that grant permissions)
- Identify any admin/owner patterns
- Identify any cross-module calls
- Estimate complexity: LoC, number of entry points, external dependencies
Coverage Plan (mandatory):
Use checklist-router.md to derive a coverage plan listing: detected chain, protocol families, feature flags, reference files loaded, and required follow-up passes. If a route fires, load the file.
Entry Point Classification: Attack surface differs by chain:
| Visibility | Sui (PTB-callable?) | Aptos (tx entry?) |
|------------|---------------------|-------------------|
| public entry fun | Yes — PTB + direct tx | Yes — transaction entry |
| public fun | Yes — PTB-callable! | No — module-callable only |
| entry fun | Yes — direct tx only | Yes — transaction only |
| public(package) fun | No — package-internal | No — package-internal |
| fun (private) | No | No |
Critical Sui distinction: ALL public fun on Sui are PTB-callable, making Sui's attack surface larger than Aptos.
Access Control Classification — for each entry point:
signer::address_of compared to stored address → Role-based; exists<*Cap>(addr) → Capability-based; &signer with NO address check → Review Required (see APT-24)Build Detection & Test Log Analysis (conditional):
Check if the project builds (Move.toml + sui move build or aptos move compile). If build succeeds (BUILD_AVAILABLE = true), run Test Log Analysis (common-move.md Section 13) to detect arithmetic aborts, assertion failures, and runtime anomalies. If build fails, note errors and skip.
Output a one-paragraph codebase summary (include build status) before proceeding.
Perspective 1 — The Attacker For each entry function:
assert! by constructing a specific state?public entry fun accept &signer without ever calling signer::address_of for authorization? → APT-24public fun (not just entry)? If so, it's PTB-composable — can it be chained with other calls to bypass per-call limits or create unexpected state?Perspective 2 — The Protocol Designer
Perspective 3 — The Integrator
Perspective 4 — The Symmetry Checker For every pair of inverse operations, verify symmetry:
withdraw(deposit(X)) <= X always (rounding favors protocol)repay(borrow(X)) >= X always (rounding favors protocol)burn(mint(X)) <= X alwaysPerspective 5 — The Bidirectional Admin Checker For every admin/privileged function that affects user funds or state, analyze BOTH directions:
counter == 0 may be griefable by users (Direction 2) AND may confiscate from passive users whose entitlement isn't tracked by the counter (Direction 1).Perspective 6 — The Consistency Checker
When a module uses an explicit safety pattern (e.g., EDivideByZero guard before division, bounds check on construction params, assert!(amount > 0) on inputs), check if sibling modules in the same package follow the same pattern. Inconsistencies are Low.
Before starting the per-check scan, confirm the coverage plan from checklist-router.md
is complete. If the codebase contains a signal with no corresponding deep check loaded,
fix the plan first.
Work through every check in common-move.md, then the chain-specific reference. For each check:
Do not skip checks. A clean check is still a check — mark it ✅.
Fixed-Point Library Inspection Gate (MANDATORY — #1 missed critical bug class):
Before completing Phase 3, you MUST complete ALL steps and output confirmation:
float, decimal, wad, ray, fixed_point, Decimal, WAD, Floatmul, div, from — do NOT assume from namemul(a,b): write the intermediate expression, simplify to raw input constraint (e.g., A * B <= U64_MAX)mul(). For each A.mul(B) chain: can A * B exceed the bound with realistic values? (token decimals: USDC=6, SUI=9, APT=8). Compute threshold table per DEFI-85Skipping this gate = missing permanent-deadlock bugs. See 2.6, 12.1, DEFI-85–87.
Dead Code / Unreachable Branch Detection: Before recording any finding that depends on a specific code branch:
if (!X) { continue } exists but X is invariantly true due to
constructor/setter validation, the entire path after the guard is dead code.If the protocol involves tokens, swaps, lending, staking, or oracles:
defi-vectors.md and run cross-cutting DeFi checks (DEFI-01 to DEFI-10)defi-vectors.md, read relevant defi/*.md filesIf the protocol has multiple accounting variables, reward indices/accumulators, checkpoints, or lending state across modules — read semantic-gap-checks.md and run this phase. Mandatory for lending, staking, vault, reward, liquidation, and oracle-heavy protocols.
Required outputs: writer path, stale/mismatched consumer path, persistence window, numeric trace for any High/Critical candidate.
After completing per-file analysis, explicitly trace these interaction pairs. For each pair, ask: does function A in module X leave module Y in an inconsistent or permanently broken state?
Required pairs to check in every lending protocol audit.
CHECK #1 IS HIGHEST PRIORITY — do it first, do it thoroughly:
[CRITICAL PRIORITY] reward_manager_update ↔ all lending operations —
Does the reward/accumulator update perform arithmetic that can abort BEFORE writing
last_update_time? If ALL user operations (deposit/withdraw/borrow/repay/liquidate/claim)
AND admin recovery (cancel/close) call this update → permanent deadlock.
(→ 12.1, DEFI-85–87). Trace: overflow bounds, checkpoint ordering, admin recovery paths, threshold table.
repay ↔ rewards/liquidity_mining — When repay fully clears the last debt on an obligation (permissionless path), is the reward tracker for that obligation cleaned up? If not: orphaned tracker may block pool closure. (→ common-move.md 11.1)
liquidate ↔ reserve (collateral reserve) —
Does the liquidation path check that the collateral reserve has
idle cash >= seize_amount before calling balance::split() or equivalent?
If not: liquidation reverts at high utilization → bad debt accumulates. (→ DEFI-81)
adl ↔ emode — Does the ADL entry condition and the ADL stop condition both read total borrows from the same source (both reserve-level OR both emode-group-level)? If different sources → wrongful liquidation or stuck ADL state. (→ DEFI-82)
admin_config ↔ interest/reserve —
Does every admin function that updates a rate model or fee rate call
accrue_interest() before applying the new value?
If not → retroactive rate application, mispriced interest for all users. (→ DEFI-80)
liquidate ↔ close_factor — Is the close factor enforced per-TRANSACTION, not per-call? On Sui, PTBs allow calling liquidate() N times atomically. If close factor is checked against current (shrinking) debt, total liquidation = 1-(1-CF)^N. (→ SUI-28, DEFI-83)
admin_config ↔ rate_limiters — Does the config update function preserve accumulated runtime state (limiter segments, accumulators, counters)? If config update resets limiters → sandwich attack; if reducers only touch the current segment → rollover griefing. (→ DEFI-84, DEFI-90)
oracle_eligibility ↔ oracle_seize — Does liquidation use the same price type for both trigger and seize, OR enforce a bounded divergence between them? If borrow/withdraw enforce EMA-spot tolerance but liquidation does NOT → unbounded price divergence in the only operational code path during volatility. (→ DESIGN-L1 caveat)
flash_loan ↔ deposit/borrow/withdraw — Do operations during an active flash loan see stale accounting fields (cash, total_borrows)? If hot potato guarantees repayment, not updating cash is intentional (DESIGN-L2). But if other operations READ the stale value mid-PTB, they may misprice shares or health. (→ DESIGN-L2 caveat)
For any interaction pair where the answer is NO → report as HIGH. This phase is mandatory. Do not skip it even if all per-file scans were clean.
Before reporting, every candidate finding from Phases 3-6 must survive a Move-expert verification pass. This phase eliminates false positives, corrects inflated severities, and ensures only real, exploitable findings reach the report.
Before verifying any finding, read verification-policy.md, evidence-chains.md,
and confidence-gates.md. Apply:
Step 1 — Dual Narrative Test
For each candidate finding, write two concrete stories:
Rule: If you cannot write a concrete attacker story with specific Move function calls, object/resource interactions, and a quantified outcome — the finding is invalid. Move's strict type system means vague "an attacker could..." stories are insufficient.
Step 2 — Move-Expert Disproof (8 Dimensions)
Systematically challenge each finding against Move's unique properties:
Move Type System & Linearity — Does Move's linear type system, borrow checker, or ability constraints already prevent this? Key Move eliminators:
key only, no copy)Call Path Completeness — Trace the full call path including
public(package)/public(friend) visibility. Does an upstream function already
validate the input? Does a downstream assert! or abort prevent the exploit?
Does the return type force the caller to handle it (hot-potato pattern)?
Object/Resource Model — Sui: is the target owned (only owner can access),
shared (consensus-ordered), wrapped (inaccessible), or frozen (immutable)?
Aptos: does acquires enforce exclusive access? Does exists<T>(addr) check
prevent the setup? Ownership often makes EVM-style attacks infeasible.
Execution Model Reality — Move has no delegatecall, no callbacks, no dynamic
dispatch, no inline assembly. Sui PTBs compose only through public interfaces —
they cannot call public(package) functions. Does the finding assume EVM capabilities
that Move doesn't have?
Precondition Feasibility & Invariant Reachability — Can the attacker reach the vulnerable state on mainnet?
assert!(a < b) on u64 makes b = 0 impossible).Economic Rationality — Attack profit vs total cost (gas, flash loan fees, capital
lockup, slippage, MEV competition). If cost >= profit, downgrade to Info. For Sui
sandwich attacks: is the attacker a validator?
Existing Protections Missed — Did the scanner overlook:
assert! conditions in the function or its calleesspec blocks enforcing invariantsCounterfactual Fix Test — Apply your recommended fix mentally:
Step 3 — Label Each Finding
confirmed or likely.needs_review. Max severity: Medium.[CODE], [TEST], [PROD-SOURCE], [PROD-STATE]).Step 4 — Mandatory Kill Questions
Every finding labeled VALID or QUESTIONABLE must answer ALL of these. If any answer is "no" or uncertain, downgrade or dismiss:
defi/defi-lending-design-patterns.md and check whether this is a
known-good design. Explain why THIS protocol's context differs if reporting.move-fp-catalog.md Section 3. If any check fails → INVALID.Step 5 — Root-Cause Deduplication
Before finalizing the finding list, group by the single LINE OF CODE that would need to change, not by downstream effect:
Keep only the highest-impact framing of each root cause.
Step 6 — Post-Confirmation Parallel Subsystem Check
After confirming any finding at Medium+ severity, check for parallel instances:
This is mandatory because bugs in shared logic affect ALL consumers, not just the first path discovered.
Evidence Audit (mandatory): For every non-trivial finding, include a short evidence
table from verification-policy.md showing each decisive claim and its source tag.
Output rules: Only VALID and QUESTIONABLE findings proceed to Phase 8. DISMISSED findings go to "Verified Clean Checks" with dismissal reason. OVERCLASSIFIED findings proceed at adjusted severity.
Produce a structured audit report in this exact format:
## Audit Report — [Module/Protocol Name]
**Chain:** Sui | Aptos
**Date:** [today]
**Severity Summary:** X Critical, X High, X Medium, X Low, X Info
**Triage Summary:** N candidates → X VALID, Y QUESTIONABLE, Z DISMISSED, W reclassified
---
### [SEVERITY-NNN] Finding Title
| Field | Value |
|------------|-------|
| Severity | Critical / High / Medium / Low / Info |
| Confidence | VALID (`confirmed`/`likely`) / QUESTIONABLE (`needs_review`) |
| Location | module_name.move, line N, function name |
| Category | [Access Control / Arithmetic / Resource Safety / etc.] |
**Description:**
Clear explanation of what the vulnerability is and why it exists.
**Attack Scenario (PoC):**
Step-by-step exploitation using Move-specific primitives with concrete values.
**Verification:** Disproof dimensions challenged and passed.
**Recommended Fix:**
Concrete code-level recommendation. Show the fix, not just the concept.
---
After all findings, add ## Verified Clean Checks (with DISMISSED findings and reasoning) and ## Auditor Notes (code quality, centralization, upgrade risks).
| Level | Criteria | |----------|----------| | Critical | Direct loss of funds, unauthorized minting, permanent protocol takeover | | High | Significant fund loss under realistic conditions, major access control bypass | | Medium | Partial fund loss, requires specific conditions, breaks core invariants | | Low | Minor issues, best-practice violations, low-probability edge cases | | Info | Code quality, gas inefficiency, documentation gaps, non-exploitable patterns |
Likelihood × Impact = Severity. A theoretically catastrophic bug that requires a nation-state adversary is not Critical. A low-impact bug that's trivially exploitable is Medium, not Low.
Admin-origin latent user DoS: Never dismiss a bug as "admin-only" or "trusted setup" if the admin action is routine (e.g., adding a reward program, setting a fee rate) and unprivileged users or liquidators are later bricked. Severity is based on who is blocked and what is blocked (fund lock, liquidation failure), not on who created the initial configuration. See common-move.md 12.2.
testing
Create, edit, improve, or audit AgentSkills. Use when creating a new skill from scratch or when asked to improve, review, audit, tidy up, or clean up an existing skill or SKILL.md file. Also use when editing or restructuring a skill directory (moving files to references/ or scripts/, removing stale content, validating against the AgentSkills spec). Triggers on phrases like "create a skill", "author a skill", "tidy up a skill", "improve this skill", "review the skill", "clean up the skill", "audit the skill".
testing
Host security hardening and risk-tolerance configuration for OpenClaw deployments. Use when a user asks for security audits, firewall/SSH/update hardening, risk posture, exposure review, OpenClaw cron scheduling for periodic checks, or version status checks on a machine running OpenClaw (laptop, workstation, Pi, VPS).
testing
Create, edit, improve, or audit AgentSkills. Use when creating a new skill from scratch or when asked to improve, review, audit, tidy up, or clean up an existing skill or SKILL.md file. Also use when editing or restructuring a skill directory (moving files to references/ or scripts/, removing stale content, validating against the AgentSkills spec). Triggers on phrases like "create a skill", "author a skill", "tidy up a skill", "improve this skill", "review the skill", "clean up the skill", "audit the skill".
testing
Host security hardening and risk-tolerance configuration for OpenClaw deployments. Use when a user asks for security audits, firewall/SSH/update hardening, risk posture, exposure review, OpenClaw cron scheduling for periodic checks, or version status checks on a machine running OpenClaw (laptop, workstation, Pi, VPS).