关于 security-audit
security-audit 是用于部署前审查 Move 合约的技能,按安全清单检查代码、测试覆盖率并整理审计报告。
主要功能
- 01七类安全检查清单
- 02访问控制与输入验证审查
- 03对象、引用、算术和类型安全检查
- 04测试覆盖率与错误路径审查
- 05审计报告模板及命令
适用场景
- 01部署前审查 Move 模块
- 02检查签名者及对象所有权控制
- 03识别算术与输入验证风险
- 04编写安全审计报告
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ aptos-labs/ aptos-agent-skills --skill security-audit安装后在 Claude Code 中输入/security-audit确认已加载。
详细介绍
安全审计技能
概述
此技能使用全面的检查清单,对 Move 合约进行系统性安全审计。部署前必须通过 所有检查项。
**重要:**安全不容妥协。用户资金取决于实现是否正确。
核心工作流
第 1 步:运行安全检查清单
按顺序检查所有类别:
- 访问控制 - 谁可以调用函数?
- 输入验证 - 是否检查了输入?
- 对象安全 - 是否正确使用了对象模型?
- 引用安全 - 是否暴露了危险引用?
- 算术安全 - 是否防止了溢出/下溢?
- 泛型类型安全 - 是否正确使用了幻影类型?
- 测试 - 是否达到 100% 覆盖率?
第 2 步:访问控制审计
验证:
- 所有
entry函数都会验证签名者权限 - 使用
object::owner()检查对象所有权 - 管理员函数会检查调用者是否为管理员
- 函数可见性遵循最小权限原则
- 没有未经检查就修改状态的公共函数
检查:
// ✅ 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!
}
对于对象:
// ✅ 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!
}
第 3 步:输入验证审计
验证:
- 检查数值输入是否为零:
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)
检查:
// ✅ 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!
}
第 4 步:对象安全审计
验证:
- 公共函数绝不返回 ConstructorRef
- 所有引用(TransferRef、DeleteRef、ExtendRef)都在构造函数中生成
- 对象签名者仅在构造期间或与 ExtendRef 配合使用
- 除非明确需要,否则禁用无门控转移
- 仅为确实可销毁的对象生成 DeleteRef
检查:
// ❌ 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)
}
第 5 步:引用安全审计
验证:
- 公共函数签名中不暴露任何
&mut引用 - 关键字段受到保护,避免被
mem::swap交换 - 尽可能缩小可变借用的作用域
检查:
// ❌ 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;
}
第 6 步:算术安全审计
验证:
- 检查加法是否会溢出
- 检查减法是否会下溢
- 防止除以零
- 检查乘法是否会溢出
检查:
// ✅ 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!
}
第 7 步:泛型类型安全审计
验证:
- 使用幻影类型作为类型见证:
struct Vault<phantom CoinType> - 泛型约束恰当:
<T: copy + drop> - 不存在类型混淆的可能
检查:
// ✅ 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,
}
第 8 步:测试审计
验证:
- 达到 100% 行覆盖率:
aptos move test --coverage - 使用
#[expected_failure]测试所有错误路径 - 使用多个签名者测试访问控制
- 使用无效输入测试输入验证
- 覆盖边界情况(最大值、空向量等)
运行:
aptos move test --coverage
aptos move coverage source --module <module_name>
确认输出显示覆盖率为 100%。
安全审计报告模板
按以下格式生成报告:
# 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.
常见漏洞
| 漏洞 | 检测方式 | 影响 | 修复方法 |
|---|---|---|---|
| 缺少访问控制 | 入口函数中没有 assert!(signer...) | 严重 — 任何人都可以调用 | 添加签名者验证 |
| 缺少所有权检查 | 没有 assert!(object::owner...) | 严重 — 任何人都可以修改任何对象 | 添加所有权检查 |
| 整数溢出 | 加法前没有检查 | 严重 — 余额会回绕为 0 | 检查 assert!(a <= MAX - b, E_OVERFLOW) |
| 整数下溢 | 减法前没有检查 | 严重 — 余额会回绕为 MAX | 检查 assert!(a >= b, E_UNDERFLOW) |
| 返回 ConstructorRef | 函数返回 ConstructorRef | 严重 — 调用者可以销毁对象 | 改为返回 Object<T> |
| 暴露 &mut | 公共函数返回 &mut T | 高 — 可能遭受 mem::swap 攻击 | 仅暴露特定操作 |
| 未验证输入 | 接受任意值 | 中 — 金额为零、溢出 | 验证所有输入 |
| 测试覆盖率低 | 覆盖率 < 100% | 中 — 生产环境中出现错误 | 编写更多测试 |
自动化检查
将这些命令作为审计的一部分运行:
# 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
手动检查
检查代码中的以下内容:
-
访问控制:
- 搜索
entry fun→ 验证每个函数都有签名者检查 - 搜索
borrow_global_mut→ 验证使用前已进行授权
- 搜索
-
输入验证:
- 搜索函数参数 → 验证参数经过检查
- 查找
amount、length、address参数 → 验证是否有检查
-
对象安全性:
- 搜索
ConstructorRef→ 验证它绝不会被返回 - 搜索
create_object→ 验证引用的生成方式正确
- 搜索
-
算术运算:
- 搜索
+→ 验证有溢出检查 - 搜索
-→ 验证有下溢检查 - 搜索
/→ 验证有除零检查
- 搜索
务必遵守的规则
- ✅ 部署前务必完成完整的安全检查清单
- ✅ 务必确认测试覆盖率达到 100%
- ✅ 务必检查入口函数中的访问控制
- ✅ 务必验证所有输入
- ✅ 务必防范溢出和下溢
- ✅ 务必生成审计报告
- ✅ 部署前务必修复严重问题
绝不遵守的规则
- ❌ 部署前绝不跳过安全审计
- ❌ 绝不忽略未通过的安全检查
- ❌ 测试覆盖率低于 100% 时绝不部署
- ❌ 绝不批准存在严重漏洞的代码
- ❌ 绝不仓促进行安全审查
- ❌ 审计期间绝不读取
~/.aptos/config.yaml或.env文件(其中包含私钥) - ❌ 绝不显示或复述审计中发现的私钥值
参考资料
模式文档:
../../../patterns/move/SECURITY.md- 全面的安全指南../../../patterns/move/OBJECTS.md- 对象安全模式
官方文档:
相关技能:
generate-tests- 确保存在测试write-contracts- 应用安全模式deploy-contracts- 部署前的最终检查
请记住: 安全问题不容妥协。检查清单中的每一项都必须通过。用户资金的安全取决于此。
评论
支持 Markdown