Security Audit

Audits Move contracts for security vulnerabilities before deployment using 7-category checklist. Triggers on: 'audit contract', 'security check', 'review sec...

MIT-0 · Free to use, modify, and redistribute. No attribution required.
0 · 82 · 0 current installs · 0 all-time installs
MIT-0
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
medium confidence
Purpose & Capability
Name, description, and SKILL.md are all focused on auditing Move contracts with a 7-category checklist (access control, input validation, object/ref/arithmetic safety, testing). Nothing in the metadata or requirements asks for unrelated credentials, binaries, or config paths.
Instruction Scope
SKILL.md is an extensive, checklist-style audit guide and includes code examples. It does not declare commands, binaries, or external services to run the checks. This keeps the skill minimal but also a bit vague: it implicitly requires the agent to inspect Move source, test results, and possibly run local tools (e.g., unit tests, Move prover) but does not specify how to access those artifacts or what to execute. That vagueness grants the agent discretion to read project files or invoke local tooling at runtime.
Install Mechanism
No install spec (instruction-only), so nothing will be downloaded or written to disk by the skill itself.
Credentials
The skill requests no environment variables, credentials, or config paths. For an audit checklist that produces guidance only, this is proportionate.
Persistence & Privilege
always is false and model invocation is allowed (platform default). The skill does not request persistent system presence or to modify other skills or global configs.
Assessment
This skill appears to be a coherent, instruction-only Move contract audit checklist and does not request secrets or install code. Before installing or running it, consider: 1) Review the full SKILL.md to confirm there are no hidden steps that upload source code or call external services. 2) Decide where the agent will run: if it will inspect your repository or run tests, run it in an isolated environment without access to private keys or production credentials. 3) If you want automated checks (running Move prover, unit tests, coverage tools), prefer a skill that explicitly declares required binaries and commands so you know what will be executed. 4) Ask the publisher for provenance (homepage, source repo) if you need accountability. If any runtime behavior will access your codebase or CI, restrict the agent's filesystem and network access accordingly.

Like a lobster shell, security has layers — review code before you run it.

Current versionv1.0.0
Download zip
latestvk975a0bnk1pasm8zk92wyc41fd837c7s

License

MIT-0
Free to use, modify, and redistribute. No attribution required.

SKILL.md

Security Audit Skill

Overview

This skill performs systematic security audits of Move contracts using a comprehensive checklist. Every item must pass before deployment.

Critical: Security is non-negotiable. User funds depend on correct implementation.

Core Workflow

Step 1: Run Security Checklist

Review ALL categories in order:

  1. Access Control - Who can call functions?
  2. Input Validation - Are inputs checked?
  3. Object Safety - Object model used correctly?
  4. Reference Safety - No dangerous references exposed?
  5. Arithmetic Safety - Overflow/underflow prevented?
  6. Generic Type Safety - Phantom types used correctly?
  7. Testing - 100% coverage achieved?

Step 2: Access Control Audit

Verify:

  • All entry functions verify signer authority
  • Object ownership checked with object::owner()
  • Admin functions check caller is admin
  • Function visibility uses least-privilege
  • No public functions modify state without checks

Check for:

// ✅ CORRECT: Signer verification
public entry fun update_config(admin: &signer, value: u64) acquires Config {
    let config = borrow_global<Config>(@my_addr);
    assert!(signer::address_of(admin) == config.admin, E_NOT_ADMIN);
    // Safe to proceed
}

// ❌ WRONG: No verification
public entry fun update_config(admin: &signer, value: u64) acquires Config {
    let config = borrow_global_mut<Config>(@my_addr);
    config.value = value; // Anyone can call!
}

For objects:

// ✅ CORRECT: Ownership verification
public entry fun transfer_item(
    owner: &signer,
    item: Object<Item>,
    to: address
) acquires Item {
    assert!(object::owner(item) == signer::address_of(owner), E_NOT_OWNER);
    // Safe to transfer
}

// ❌ WRONG: No ownership check
public entry fun transfer_item(
    owner: &signer,
    item: Object<Item>,
    to: address
) acquires Item {
    // Anyone can transfer any item!
}

Step 3: Input Validation Audit

Verify:

  • Numeric inputs checked for zero: assert!(amount > 0, E_ZERO_AMOUNT)
  • Numeric inputs within max limits: assert!(amount <= MAX, E_AMOUNT_TOO_HIGH)
  • Vector lengths validated: assert!(vector::length(&v) > 0, E_EMPTY_VECTOR)
  • String lengths checked: assert!(string::length(&s) <= MAX_LENGTH, E_NAME_TOO_LONG)
  • Addresses validated: assert!(addr != @0x0, E_ZERO_ADDRESS)
  • Enum-like values in range: assert!(type_id < MAX_TYPES, E_INVALID_TYPE)

Check for:

// ✅ CORRECT: Comprehensive validation
public entry fun deposit(user: &signer, amount: u64) acquires Account {
    assert!(amount > 0, E_ZERO_AMOUNT);
    assert!(amount <= MAX_DEPOSIT_AMOUNT, E_AMOUNT_TOO_HIGH);

    let account = borrow_global_mut<Account>(signer::address_of(user));
    assert!(account.balance <= MAX_U64 - amount, E_OVERFLOW);

    account.balance = account.balance + amount;
}

// ❌ WRONG: No validation
public entry fun deposit(user: &signer, amount: u64) acquires Account {
    let account = borrow_global_mut<Account>(signer::address_of(user));
    account.balance = account.balance + amount; // Can overflow!
}

Step 4: Object Safety Audit

Verify:

  • ConstructorRef never returned from public functions
  • All refs (TransferRef, DeleteRef, ExtendRef) generated in constructor
  • Object signer only used during construction or with ExtendRef
  • Ungated transfers disabled unless explicitly needed
  • DeleteRef only generated for truly burnable objects

Check for:

// ❌ DANGEROUS: Returning ConstructorRef
public fun create_item(): ConstructorRef {
    let constructor_ref = object::create_object(@my_addr);
    constructor_ref // Caller can destroy object!
}

// ✅ CORRECT: Return Object<T>
public fun create_item(creator: &signer): Object<Item> {
    let constructor_ref = object::create_object(signer::address_of(creator));

    let transfer_ref = object::generate_transfer_ref(&constructor_ref);
    let delete_ref = object::generate_delete_ref(&constructor_ref);
    let object_signer = object::generate_signer(&constructor_ref);

    move_to(&object_signer, Item { transfer_ref, delete_ref });

    object::object_from_constructor_ref<Item>(&constructor_ref)
}

Step 5: Reference Safety Audit

Verify:

  • No &mut references exposed in public function signatures
  • Critical fields protected from mem::swap
  • Mutable borrows minimized in scope

Check for:

// ❌ DANGEROUS: Exposing mutable reference
public fun get_item_mut(item: Object<Item>): &mut Item acquires Item {
    borrow_global_mut<Item>(object::object_address(&item))
    // Caller can mem::swap fields!
}

// ✅ CORRECT: Controlled mutations
public entry fun update_item_name(
    owner: &signer,
    item: Object<Item>,
    new_name: String
) acquires Item {
    assert!(object::owner(item) == signer::address_of(owner), E_NOT_OWNER);

    let item_data = borrow_global_mut<Item>(object::object_address(&item));
    item_data.name = new_name;
}

Step 6: Arithmetic Safety Audit

Verify:

  • Additions checked for overflow
  • Subtractions checked for underflow
  • Division by zero prevented
  • Multiplication checked for overflow

Check for:

// ✅ CORRECT: Overflow protection
public entry fun deposit(user: &signer, amount: u64) acquires Account {
    let account = borrow_global_mut<Account>(signer::address_of(user));

    // Check overflow BEFORE adding
    assert!(account.balance <= MAX_U64 - amount, E_OVERFLOW);

    account.balance = account.balance + amount;
}

// ✅ CORRECT: Underflow protection
public entry fun withdraw(user: &signer, amount: u64) acquires Account {
    let account = borrow_global_mut<Account>(signer::address_of(user));

    // Check underflow BEFORE subtracting
    assert!(account.balance >= amount, E_INSUFFICIENT_BALANCE);

    account.balance = account.balance - amount;
}

// ❌ WRONG: No overflow check
public entry fun deposit(user: &signer, amount: u64) acquires Account {
    let account = borrow_global_mut<Account>(signer::address_of(user));
    account.balance = account.balance + amount; // Can overflow!
}

Step 7: Generic Type Safety Audit

Verify:

  • Phantom types used for type witnesses: struct Vault<phantom CoinType>
  • Generic constraints appropriate: <T: copy + drop>
  • No type confusion possible

Check for:

// ✅ CORRECT: Phantom type for safety
struct Vault<phantom CoinType> has key {
    balance: u64,
    // CoinType only for type safety, not stored
}

public fun deposit<CoinType>(vault: Object<Vault<CoinType>>, amount: u64) {
    // Type-safe: can't deposit BTC into USDC vault
}

// ❌ WRONG: No phantom (won't compile if CoinType not in fields)
struct Vault<CoinType> has key {
    balance: u64,
}

Step 8: Testing Audit

Verify:

  • 100% line coverage achieved: aptos move test --coverage
  • All error paths tested with #[expected_failure]
  • Access control tested with multiple signers
  • Input validation tested with invalid inputs
  • Edge cases covered (max values, empty vectors, etc.)

Run:

aptos move test --coverage
aptos move coverage source --module <module_name>

Verify output shows 100% coverage.

Security Audit Report Template

Generate report in this format:

# Security Audit Report

**Module:** my_module **Date:** 2026-01-23 **Auditor:** AI Assistant

## Summary

- ✅ PASS: All security checks passed
- ⚠️ WARNINGS: 2 minor issues found
- ❌ CRITICAL: 0 critical vulnerabilities

## Access Control

- ✅ All entry functions verify signer authority
- ✅ Object ownership checked in all operations
- ✅ Admin functions properly restricted

## Input Validation

- ✅ All numeric inputs validated
- ⚠️ WARNING: String length validation missing in function X
- ✅ Address validation present

## Object Safety

- ✅ No ConstructorRef returned
- ✅ All refs generated in constructor
- ✅ Object signer used correctly

## Reference Safety

- ✅ No public &mut references
- ✅ Critical fields protected

## Arithmetic Safety

- ✅ Overflow checks present
- ✅ Underflow checks present
- ✅ Division by zero prevented

## Generic Type Safety

- ✅ Phantom types used correctly
- ✅ Constraints appropriate

## Testing

- ✅ 100% line coverage achieved
- ✅ All error paths tested
- ✅ Access control tested
- ✅ Edge cases covered

## Recommendations

1. Add string length validation to function X (line 42)
2. Consider adding event emissions for important state changes

## Conclusion

✅ Safe to deploy after addressing warnings.

Common Vulnerabilities

VulnerabilityDetectionImpactFix
Missing access controlNo assert!(signer...) in entry functionsCritical - anyone can callAdd signer verification
Missing ownership checkNo assert!(object::owner...)Critical - anyone can modify any objectAdd ownership check
Integer overflowNo check before additionCritical - balance wraps to 0Check assert!(a <= MAX - b, E_OVERFLOW)
Integer underflowNo check before subtractionCritical - balance wraps to MAXCheck assert!(a >= b, E_UNDERFLOW)
Returning ConstructorRefFunction returns ConstructorRefCritical - caller can destroy objectReturn Object<T> instead
Exposing &mutPublic function returns &mut THigh - mem::swap attacksExpose specific operations only
No input validationAccept any valueMedium - zero amounts, overflowValidate all inputs
Low test coverageCoverage < 100%Medium - bugs in productionWrite more tests

Automated Checks

Run these commands as part of audit:

# Compile (check for errors)
aptos move compile

# Run tests
aptos move test

# Check coverage
aptos move test --coverage
aptos move coverage summary

# Expected: 100.0% coverage

Manual Checks

Review code for:

  1. Access Control:

    • Search for entry fun → verify each has signer checks
    • Search for borrow_global_mut → verify authorization before use
  2. Input Validation:

    • Search for function parameters → verify validation
    • Look for amount, length, address params → verify checks
  3. Object Safety:

    • Search for ConstructorRef → verify never returned
    • Search for create_object → verify refs generated properly
  4. Arithmetic:

    • Search for + → verify overflow checks
    • Search for - → verify underflow checks
    • Search for / → verify division by zero checks

ALWAYS Rules

  • ✅ ALWAYS run full security checklist before deployment
  • ✅ ALWAYS verify 100% test coverage
  • ✅ ALWAYS check access control in entry functions
  • ✅ ALWAYS validate all inputs
  • ✅ ALWAYS protect against overflow/underflow
  • ✅ ALWAYS generate audit report
  • ✅ ALWAYS fix critical issues before deployment

NEVER Rules

  • ❌ NEVER skip security audit before deployment
  • ❌ NEVER ignore failing security checks
  • ❌ NEVER deploy with < 100% test coverage
  • ❌ NEVER approve code with critical vulnerabilities
  • ❌ NEVER rush security review
  • ❌ NEVER read ~/.aptos/config.yaml or .env files during audits (contain private keys)
  • ❌ NEVER display or repeat private key values found during audit

References

Pattern Documentation:

  • ../../../patterns/move/SECURITY.md - Comprehensive security guide
  • ../../../patterns/move/OBJECTS.md - Object safety patterns

Official Documentation:

Related Skills:

  • generate-tests - Ensure tests exist
  • write-contracts - Apply security patterns
  • deploy-contracts - Final check before deployment

Remember: Security is non-negotiable. Every checklist item must pass. User funds depend on it.

Files

1 total
Select a file
Select a file to preview.

Comments

Loading comments…