security-audit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

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.
本技能使用全面的检查清单对Move合约执行系统性安全审计,部署前必须通过所有检查项。
重要提示: 安全问题不容妥协,用户资金安全取决于代码的正确实现。

Core Workflow

核心工作流

Step 1: Run Security Checklist

步骤1:执行安全检查清单

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?
按顺序检查所有类别:
  1. 访问控制 - 谁可以调用函数?
  2. 输入验证 - 输入是否经过校验?
  3. 对象安全 - 对象模型使用是否正确?
  4. 引用安全 - 没有暴露危险引用?
  5. 运算安全 - 是否防止了溢出/下溢?
  6. 泛型类型安全 - 幻影类型使用是否正确?
  7. 测试 - 是否达到100%测试覆盖率?

Step 2: Access Control Audit

步骤2:访问控制审计

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:
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
    &mut
    references exposed in public function signatures
  • 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
undefined

Security 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

  1. Add string length validation to function X (line 42)
  2. Consider adding event emissions for important state changes
  1. Add string length validation to function X (line 42)
  2. Consider adding event emissions for important state changes

Conclusion

Conclusion

✅ Safe to deploy after addressing warnings.
undefined
✅ Safe to deploy after addressing warnings.
undefined

Common Vulnerabilities

常见漏洞

VulnerabilityDetectionImpactFix
Missing access controlNo
assert!(signer...)
in entry functions
Critical - anyone can callAdd signer verification
Missing ownership checkNo
assert!(object::owner...)
Critical - anyone can modify any objectAdd ownership check
Integer overflowNo check before additionCritical - balance wraps to 0Check
assert!(a <= MAX - b, E_OVERFLOW)
Integer underflowNo check before subtractionCritical - balance wraps to MAXCheck
assert!(a >= b, E_UNDERFLOW)
Returning ConstructorRefFunction returns ConstructorRefCritical - caller can destroy objectReturn
Object<T>
instead
Exposing &mutPublic function returns
&mut T
High - mem::swap attacksExpose specific operations only
No input validationAccept any valueMedium - zero amounts, overflowValidate all inputs
Low test coverageCoverage < 100%Medium - bugs in productionWrite more tests
漏洞类型检测方式影响修复方案
缺失访问控制entry函数中没有
assert!(signer...)
校验
严重 - 任何人都可以调用添加签名者验证
缺失所有权检查没有
assert!(object::owner...)
校验
严重 - 任何人都可以修改任意对象添加所有权检查
整数溢出加法前没有检查严重 - 余额归零检查
assert!(a <= MAX - b, E_OVERFLOW)
整数下溢减法前没有检查严重 - 余额变为最大值检查
assert!(a >= b, E_UNDERFLOW)
返回ConstructorRef函数返回ConstructorRef严重 - 调用者可以销毁对象改为返回
Object<T>
暴露可变引用公共函数返回
&mut T
高危 - 存在mem::swap攻击风险仅暴露特定操作接口
无输入验证接受任意值中危 - 零金额、溢出等问题校验所有输入
测试覆盖率低覆盖率<100%中危 - 生产环境存在bug补充更多测试用例

Automated Checks

自动化检查

Run these commands as part of audit:
bash
undefined
审计过程中执行以下命令:
bash
undefined

Compile (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

undefined
undefined

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
代码审查需确认:
  1. 访问控制:
    • 搜索
      entry fun
      → 确认每个都有签名者校验
    • 搜索
      borrow_global_mut
      → 确认使用前已做授权校验
  2. 输入验证:
    • 搜索函数参数 → 确认都经过验证
    • 查找
      amount
      length
      address
      参数 → 确认有对应校验
  3. 对象安全:
    • 搜索
      ConstructorRef
      → 确认永远不会被返回
    • 搜索
      create_object
      → 确认引用生成方式正确
  4. 运算:
    • 搜索
      +
      → 确认有溢出检查
    • 搜索
      -
      → 确认有下溢检查
    • 搜索
      /
      → 确认有除零检查

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
    ~/.aptos/config.yaml
    or
    .env
    files during audits (contain private keys)
  • ❌ NEVER display or repeat private key values found during audit
  • ❌ 部署前绝不跳过安全审计
  • ❌ 绝不忽略失败的安全检查
  • ❌ 绝不部署测试覆盖率低于100%的代码
  • ❌ 绝不批准存在严重漏洞的代码
  • ❌ 绝不仓促完成安全审查
  • ❌ 审计过程中绝不读取
    ~/.aptos/config.yaml
    .env
    文件(包含私钥)
  • ❌ 绝不展示或重复审计过程中发现的私钥值

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 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.
模式文档:
  • ../../../patterns/move/SECURITY.md
    - 全面安全指南
  • ../../../patterns/move/OBJECTS.md
    - 对象安全模式
官方文档:
相关技能:
  • generate-tests
    - 确保测试用例存在
  • write-contracts
    - 应用安全模式
  • deploy-contracts
    - 部署前最终检查

谨记: 安全问题不容妥协,必须通过所有检查项,用户的资金安全取决于此。