mcpField
S
security-audit

security-audit

github.com/aptos-labs安全2093 次安装24 周前更新
代码仓库

关于 security-audit

security-audit 是用于部署前审查 Move 合约的技能,按安全清单检查代码、测试覆盖率并整理审计报告。

主要功能

  1. 01七类安全检查清单
  2. 02访问控制与输入验证审查
  3. 03对象、引用、算术和类型安全检查
  4. 04测试覆盖率与错误路径审查
  5. 05审计报告模板及命令

适用场景

  1. 01部署前审查 Move 模块
  2. 02检查签名者及对象所有权控制
  3. 03识别算术与输入验证风险
  4. 04编写安全审计报告

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/aptos-labs/aptos-agent-skills --skill security-audit

安装后在 Claude Code 中输入/security-audit确认已加载。

详细介绍

安全审计技能

概述

此技能使用全面的检查清单,对 Move 合约进行系统性安全审计。部署前必须通过 所有检查项。

**重要:**安全不容妥协。用户资金取决于实现是否正确。

核心工作流

第 1 步:运行安全检查清单

按顺序检查所有类别:

  1. 访问控制 - 谁可以调用函数?
  2. 输入验证 - 是否检查了输入?
  3. 对象安全 - 是否正确使用了对象模型?
  4. 引用安全 - 是否暴露了危险引用?
  5. 算术安全 - 是否防止了溢出/下溢?
  6. 泛型类型安全 - 是否正确使用了幻影类型?
  7. 测试 - 是否达到 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

手动检查

检查代码中的以下内容:

  1. 访问控制:

    • 搜索 entry fun → 验证每个函数都有签名者检查
    • 搜索 borrow_global_mut → 验证使用前已进行授权
  2. 输入验证:

    • 搜索函数参数 → 验证参数经过检查
    • 查找 amount、length、address 参数 → 验证是否有检查
  3. 对象安全性:

    • 搜索 ConstructorRef → 验证它绝不会被返回
    • 搜索 create_object → 验证引用的生成方式正确
  4. 算术运算:

    • 搜索 + → 验证有溢出检查
    • 搜索 - → 验证有下溢检查
    • 搜索 / → 验证有除零检查

务必遵守的规则

  • ✅ 部署前务必完成完整的安全检查清单
  • ✅ 务必确认测试覆盖率达到 100%
  • ✅ 务必检查入口函数中的访问控制
  • ✅ 务必验证所有输入
  • ✅ 务必防范溢出和下溢
  • ✅ 务必生成审计报告
  • ✅ 部署前务必修复严重问题

绝不遵守的规则

  • ❌ 部署前绝不跳过安全审计
  • ❌ 绝不忽略未通过的安全检查
  • ❌ 测试覆盖率低于 100% 时绝不部署
  • ❌ 绝不批准存在严重漏洞的代码
  • ❌ 绝不仓促进行安全审查
  • ❌ 审计期间绝不读取 ~/.aptos/config.yaml 或 .env 文件(其中包含私钥)
  • ❌ 绝不显示或复述审计中发现的私钥值

参考资料

模式文档:

  • ../../../patterns/move/SECURITY.md - 全面的安全指南
  • ../../../patterns/move/OBJECTS.md - 对象安全模式

官方文档:

相关技能:

  • generate-tests - 确保存在测试
  • write-contracts - 应用安全模式
  • deploy-contracts - 部署前的最终检查

请记住: 安全问题不容妥协。检查清单中的每一项都必须通过。用户资金的安全取决于此。

评论

支持 Markdown