security-audit
11
总安装量
5
周安装量
#28590
全站排名
安装命令
npx skills add https://github.com/iskysun96/aptos-agent-skills --skill security-audit
Agent 安装分布
amp
4
opencode
4
kimi-cli
4
codex
4
github-copilot
4
gemini-cli
4
Skill 文档
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:
- Access Control – Who can call functions?
- Input Validation – Are inputs checked?
- Object Safety – Object model used correctly?
- Reference Safety – No dangerous references exposed?
- Arithmetic Safety – Overflow/underflow prevented?
- Generic Type Safety – Phantom types used correctly?
- Testing – 100% coverage achieved?
Step 2: Access Control Audit
Verify:
- All
entryfunctions 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
&mutreferences 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
| 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<T> 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:
-
Access Control:
- Search for
entry funâ verify each has signer checks - Search for
borrow_global_mutâ verify authorization before use
- Search for
-
Input Validation:
- Search for function parameters â verify validation
- Look for
amount,length,addressparams â verify checks
-
Object Safety:
- Search for
ConstructorRefâ verify never returned - Search for
create_objectâ verify refs generated properly
- Search for
-
Arithmetic:
- Search for
+â verify overflow checks - Search for
-â verify underflow checks - Search for
/â verify division by zero checks
- Search for
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.yamlor.envfiles 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 existwrite-contracts– Apply security patternsdeploy-contracts– Final check before deployment
Remember: Security is non-negotiable. Every checklist item must pass. User funds depend on it.