🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Security Audit

by @iskysun96

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

Versionv1.0.0
Downloads474
TERMINAL
clawhub install aptos-security-audit

πŸ“– About This Skill


name: security-audit description: "Audits Move contracts for security vulnerabilities before deployment using 7-category checklist. Triggers on: 'audit contract', 'security check', 'review security', 'check for vulnerabilities', 'security audit', 'is this secure', 'find security issues'." license: MIT metadata: author: aptos-labs version: "1.0" category: move tags: ["security", "audit", "vulnerabilities", "best-practices"] priority: critical

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(@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(@my_addr); config.value = value; // Anyone can call! }

    For objects:

    // βœ… CORRECT: Ownership verification
    public entry fun transfer_item(
        owner: &signer,
        item: Object,
        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, 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(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(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 public fun create_item(creator: &signer): Object { 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(&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): &mut Item acquires Item {
        borrow_global_mut(object::object_address(&item))
        // Caller can mem::swap fields!
    }

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

    let item_data = borrow_global_mut(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(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(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(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
  • [ ] Generic constraints appropriate:
  • [ ] No type confusion possible
  • Check for:

    // βœ… CORRECT: Phantom type for safety
    struct Vault has key {
        balance: u64,
        // CoinType only for type safety, not stored
    }

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

    // ❌ WRONG: No phantom (won't compile if CoinType not in fields) struct Vault 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 
    

    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

    | Vulnerability | Detection | Impact | Fix | | ------------------------ | ------------------------------------------ | --------------------------------------- | ----------------------------------------- | | Missing access control | No assert!(signer...) in entry functions | Critical - anyone can call | Add signer verification | | Missing ownership check | No assert!(object::owner...) | Critical - anyone can modify any object | Add ownership check | | Integer overflow | No check before addition | Critical - balance wraps to 0 | Check assert!(a <= MAX - b, E_OVERFLOW) | | Integer underflow | No check before subtraction | Critical - balance wraps to MAX | Check assert!(a >= b, E_UNDERFLOW) | | Returning ConstructorRef | Function returns ConstructorRef | Critical - caller can destroy object | Return Object instead | | Exposing &mut | Public function returns &mut T | High - mem::swap attacks | Expose specific operations only | | No input validation | Accept any value | Medium - zero amounts, overflow | Validate all inputs | | Low test coverage | Coverage < 100% | Medium - bugs in production | Write 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:

  • https://aptos.dev/build/smart-contracts/move-security-guidelines
  • 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.