security-audit
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSecurity 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.
本技能使用全面的检查清单对Move合约执行系统性安全审计,部署前必须通过所有检查项。
重要提示: 安全问题不容妥协,用户资金安全取决于代码的正确实现。
Core Workflow
核心工作流
Step 1: Run Security Checklist
步骤1:执行安全检查清单
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?
按顺序检查所有类别:
- 访问控制 - 谁可以调用函数?
- 输入验证 - 输入是否经过校验?
- 对象安全 - 对象模型使用是否正确?
- 引用安全 - 没有暴露危险引用?
- 运算安全 - 是否防止了溢出/下溢?
- 泛型类型安全 - 幻影类型使用是否正确?
- 测试 - 是否达到100%测试覆盖率?
Step 2: Access Control Audit
步骤2:访问控制审计
Verify:
- All functions verify signer authority
entry - 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:
move
// ✅ 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:
move
// ✅ 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!
}验证项:
- 所有函数都验证签名者权限
entry - 使用校验对象所有权
object::owner() - 管理员函数校验调用者是否为管理员
- 函数可见性遵循最小权限原则
- 没有公共函数在未校验的情况下修改状态
检查示例:
move
// ✅ 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!
}对象相关检查:
move
// ✅ 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
步骤3:输入验证审计
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:
move
// ✅ 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!
}验证项:
- 数值输入校验非零:
assert!(amount > 0, E_ZERO_AMOUNT) - 数值输入不超过最大限制:
assert!(amount <= MAX, E_AMOUNT_TOO_HIGH) - 向量长度校验:
assert!(vector::length(&v) > 0, E_EMPTY_VECTOR) - 字符串长度校验:
assert!(string::length(&s) <= MAX_LENGTH, E_NAME_TOO_LONG) - 地址校验:
assert!(addr != @0x0, E_ZERO_ADDRESS) - 类枚举值在有效范围内:
assert!(type_id < MAX_TYPES, E_INVALID_TYPE)
检查示例:
move
// ✅ 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
步骤4:对象安全审计
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:
move
// ❌ 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)
}验证项:
- ConstructorRef永远不会从公共函数返回
- 所有引用(TransferRef、DeleteRef、ExtendRef)都在构造函数中生成
- 对象签名者仅在构造期间或配合ExtendRef使用
- 除非明确需要,否则禁用无限制转账
- 仅为可真正销毁的对象生成DeleteRef
检查示例:
move
// ❌ 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
步骤5:引用安全审计
Verify:
- No references exposed in public function signatures
&mut - Critical fields protected from
mem::swap - Mutable borrows minimized in scope
Check for:
move
// ❌ 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;
}验证项:
- 公共函数签名中没有暴露引用
&mut - 关键字段受保护,避免攻击
mem::swap - 可变借用的作用域最小化
检查示例:
move
// ❌ 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
步骤6:运算安全审计
Verify:
- Additions checked for overflow
- Subtractions checked for underflow
- Division by zero prevented
- Multiplication checked for overflow
Check for:
move
// ✅ 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!
}验证项:
- 加法检查溢出
- 减法检查下溢
- 防止除零错误
- 乘法检查溢出
检查示例:
move
// ✅ 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
步骤7:泛型类型安全审计
Verify:
- Phantom types used for type witnesses:
struct Vault<phantom CoinType> - Generic constraints appropriate:
<T: copy + drop> - No type confusion possible
Check for:
move
// ✅ 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,
}验证项:
- 幻影类型用作类型见证:
struct Vault<phantom CoinType> - 泛型约束合理:
<T: copy + drop> - 不存在类型混淆的可能
检查示例:
move
// ✅ 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
步骤8:测试审计
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:
bash
aptos move test --coverage
aptos move coverage source --module <module_name>Verify output shows 100% coverage.
验证项:
- 达到100%行覆盖率:
aptos move test --coverage - 所有错误路径都通过测试
#[expected_failure] - 使用多个签名者测试访问控制
- 使用无效输入测试输入验证
- 覆盖边界情况(最大值、空向量等)
执行命令:
bash
aptos move test --coverage
aptos move coverage source --module <module_name>验证输出显示100%覆盖率。
Security Audit Report Template
安全审计报告模板
Generate report in this format:
markdown
undefined按以下格式生成报告:
markdown
undefinedSecurity Audit Report
Security Audit Report
Module: my_module Date: 2026-01-23 Auditor: AI Assistant
Module: my_module Date: 2026-01-23 Auditor: AI Assistant
Summary
Summary
- ✅ PASS: All security checks passed
- ⚠️ WARNINGS: 2 minor issues found
- ❌ CRITICAL: 0 critical vulnerabilities
- ✅ PASS: All security checks passed
- ⚠️ WARNINGS: 2 minor issues found
- ❌ CRITICAL: 0 critical vulnerabilities
Access Control
Access Control
- ✅ All entry functions verify signer authority
- ✅ Object ownership checked in all operations
- ✅ Admin functions properly restricted
- ✅ All entry functions verify signer authority
- ✅ Object ownership checked in all operations
- ✅ Admin functions properly restricted
Input Validation
Input Validation
- ✅ All numeric inputs validated
- ⚠️ WARNING: String length validation missing in function X
- ✅ Address validation present
- ✅ All numeric inputs validated
- ⚠️ WARNING: String length validation missing in function X
- ✅ Address validation present
Object Safety
Object Safety
- ✅ No ConstructorRef returned
- ✅ All refs generated in constructor
- ✅ Object signer used correctly
- ✅ No ConstructorRef returned
- ✅ All refs generated in constructor
- ✅ Object signer used correctly
Reference Safety
Reference Safety
- ✅ No public &mut references
- ✅ Critical fields protected
- ✅ No public &mut references
- ✅ Critical fields protected
Arithmetic Safety
Arithmetic Safety
- ✅ Overflow checks present
- ✅ Underflow checks present
- ✅ Division by zero prevented
- ✅ Overflow checks present
- ✅ Underflow checks present
- ✅ Division by zero prevented
Generic Type Safety
Generic Type Safety
- ✅ Phantom types used correctly
- ✅ Constraints appropriate
- ✅ Phantom types used correctly
- ✅ Constraints appropriate
Testing
Testing
- ✅ 100% line coverage achieved
- ✅ All error paths tested
- ✅ Access control tested
- ✅ Edge cases covered
- ✅ 100% line coverage achieved
- ✅ All error paths tested
- ✅ Access control tested
- ✅ Edge cases covered
Recommendations
Recommendations
- Add string length validation to function X (line 42)
- Consider adding event emissions for important state changes
- Add string length validation to function X (line 42)
- Consider adding event emissions for important state changes
Conclusion
Conclusion
✅ Safe to deploy after addressing warnings.
undefined✅ Safe to deploy after addressing warnings.
undefinedCommon Vulnerabilities
常见漏洞
| Vulnerability | Detection | Impact | Fix |
|---|---|---|---|
| Missing access control | No | Critical - anyone can call | Add signer verification |
| Missing ownership check | No | Critical - anyone can modify any object | Add ownership check |
| Integer overflow | No check before addition | Critical - balance wraps to 0 | Check |
| Integer underflow | No check before subtraction | Critical - balance wraps to MAX | Check |
| Returning ConstructorRef | Function returns ConstructorRef | Critical - caller can destroy object | Return |
| Exposing &mut | Public function returns | 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 |
| 漏洞类型 | 检测方式 | 影响 | 修复方案 |
|---|---|---|---|
| 缺失访问控制 | entry函数中没有 | 严重 - 任何人都可以调用 | 添加签名者验证 |
| 缺失所有权检查 | 没有 | 严重 - 任何人都可以修改任意对象 | 添加所有权检查 |
| 整数溢出 | 加法前没有检查 | 严重 - 余额归零 | 检查 |
| 整数下溢 | 减法前没有检查 | 严重 - 余额变为最大值 | 检查 |
| 返回ConstructorRef | 函数返回ConstructorRef | 严重 - 调用者可以销毁对象 | 改为返回 |
| 暴露可变引用 | 公共函数返回 | 高危 - 存在mem::swap攻击风险 | 仅暴露特定操作接口 |
| 无输入验证 | 接受任意值 | 中危 - 零金额、溢出等问题 | 校验所有输入 |
| 测试覆盖率低 | 覆盖率<100% | 中危 - 生产环境存在bug | 补充更多测试用例 |
Automated Checks
自动化检查
Run these commands as part of audit:
bash
undefined审计过程中执行以下命令:
bash
undefinedCompile (check for errors)
Compile (check for errors)
aptos move compile
aptos move compile
Run tests
Run tests
aptos move test
aptos move test
Check coverage
Check coverage
aptos move test --coverage
aptos move coverage summary
aptos move test --coverage
aptos move coverage summary
Expected: 100.0% coverage
Expected: 100.0% coverage
undefinedundefinedManual Checks
人工检查
Review code for:
-
Access Control:
- Search for → verify each has signer checks
entry fun - Search for → verify authorization before use
borrow_global_mut
- Search for
-
Input Validation:
- Search for function parameters → verify validation
- Look for ,
amount,lengthparams → verify checksaddress
-
Object Safety:
- Search for → verify never returned
ConstructorRef - Search for → verify refs generated properly
create_object
- Search for
-
Arithmetic:
- Search for → verify overflow checks
+ - Search for → verify underflow checks
- - Search for → verify division by zero checks
/
- Search for
代码审查需确认:
-
访问控制:
- 搜索→ 确认每个都有签名者校验
entry fun - 搜索→ 确认使用前已做授权校验
borrow_global_mut
- 搜索
-
输入验证:
- 搜索函数参数 → 确认都经过验证
- 查找、
amount、length参数 → 确认有对应校验address
-
对象安全:
- 搜索→ 确认永远不会被返回
ConstructorRef - 搜索→ 确认引用生成方式正确
create_object
- 搜索
-
运算:
- 搜索→ 确认有溢出检查
+ - 搜索→ 确认有下溢检查
- - 搜索→ 确认有除零检查
/
- 搜索
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
- ✅ 部署前必须执行完整的安全检查清单
- ✅ 必须验证100%测试覆盖率
- ✅ 必须检查entry函数的访问控制
- ✅ 必须校验所有输入
- ✅ 必须防范溢出/下溢问题
- ✅ 必须生成审计报告
- ✅ 部署前必须修复所有严重问题
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 or
~/.aptos/config.yamlfiles during audits (contain private keys).env - ❌ NEVER display or repeat private key values found during audit
- ❌ 部署前绝不跳过安全审计
- ❌ 绝不忽略失败的安全检查
- ❌ 绝不部署测试覆盖率低于100%的代码
- ❌ 绝不批准存在严重漏洞的代码
- ❌ 绝不仓促完成安全审查
- ❌ 审计过程中绝不读取或
~/.aptos/config.yaml文件(包含私钥).env - ❌ 绝不展示或重复审计过程中发现的私钥值
References
参考资料
Pattern Documentation:
- - Comprehensive security guide
../../../patterns/move/SECURITY.md - - Object safety patterns
../../../patterns/move/OBJECTS.md
Official Documentation:
Related Skills:
- - Ensure tests exist
generate-tests - - Apply security patterns
write-contracts - - Final check before deployment
deploy-contracts
Remember: Security is non-negotiable. Every checklist item must pass. User funds depend on it.
模式文档:
- - 全面安全指南
../../../patterns/move/SECURITY.md - - 对象安全模式
../../../patterns/move/OBJECTS.md
官方文档:
相关技能:
- - 确保测试用例存在
generate-tests - - 应用安全模式
write-contracts - - 部署前最终检查
deploy-contracts
谨记: 安全问题不容妥协,必须通过所有检查项,用户的资金安全取决于此。