Substrate漏洞扫描器Skill substrate-vulnerability-scanner

这个技能用于扫描Substrate/Polkadot区块链的runtime模块,检测7种关键安全漏洞,如算术溢出、panic DoS、权重错误和来源验证问题。它适用于安全审计、区块链开发、防止节点崩溃和DoS攻击,关键词包括Substrate、Polkadot、漏洞扫描、安全审计、区块链安全、FRAME pallets、权重计算、源代码分析。

链开发 0 次安装 0 次浏览 更新于 3/14/2026

name: substrate-vulnerability-scanner description: 扫描Substrate/Polkadot pallets以检测7种关键漏洞,包括算术溢出、panic DoS、不正确的权重和错误来源检查。用于审计Substrate runtimes或FRAME pallets。

Substrate漏洞扫描器

1. 目的

系统扫描Substrate runtime模块(pallets)以检测平台特定的安全漏洞,这些漏洞可能导致节点崩溃、DoS攻击或未授权访问。此技能编码了7种Substrate/FRAME基础链独有的关键漏洞模式。

2. 何时使用此技能

  • 审计自定义Substrate pallets
  • 审查FRAME runtime代码
  • Substrate链(Polkadot parachains、独立链)预发布安全评估
  • 验证可调度外部函数
  • 审查权重计算函数
  • 评估无签名交易验证逻辑

3. 平台检测

文件扩展名和指标

  • Rust文件: .rs

语言/框架标记

// Substrate/FRAME指标
#[pallet]
pub mod pallet {
    use frame_support::pallet_prelude::*;
    use frame_system::pallet_prelude::*;

    #[pallet::config]
    pub trait Config: frame_system::Config { }

    #[pallet::call]
    impl<T: Config> Pallet<T> {
        #[pallet::weight(10_000)]
        pub fn example_function(origin: OriginFor<T>) -> DispatchResult { }
    }
}

// 常见模式
DispatchResult, DispatchError
ensure!, ensure_signed, ensure_root
StorageValue, StorageMap, StorageDoubleMap
#[pallet::storage]
#[pallet::call]
#[pallet::weight]
#[pallet::validate_unsigned]

项目结构

  • pallets/*/lib.rs - Pallet实现
  • runtime/lib.rs - Runtime配置
  • benchmarking.rs - 权重基准测试
  • Cargo.toml 包含 frame-* 依赖

工具支持

  • cargo-fuzz: Rust模糊测试
  • test-fuzz: 基于属性的测试框架
  • 基准测试框架: 内置权重计算
  • try-runtime: Runtime迁移测试

4. 此技能如何工作

当调用时,我将:

  1. 搜索您的代码库以查找Substrate pallets
  2. 分析每个pallet以检测7种漏洞模式
  3. 报告发现包括文件引用和严重性
  4. 提供修复针对每个识别出的问题
  5. 检查权重计算和来源验证

5. 漏洞模式(7种关键模式)

我检查7种Substrate/FRAME独有的关键漏洞模式。有关详细检测模式、代码示例、缓解措施和测试策略,请参见VULNERABILITY_PATTERNS.md

模式摘要:

  1. 算术溢出 ⚠️ 关键

    • 直接+-*/操作符在发布模式下包装
    • 必须使用checked_*saturating_*方法
    • 影响余额/代币计算、奖励/费用数学
  2. 不Panic ⚠️ 关键 - DoS

    • Panic导致节点停止处理区块
    • unwrap()expect()、无边界检查的数组索引
    • 所有用户输入必须用ensure!验证
  3. 权重和费用 ⚠️ 关键 - DoS

    • 不正确的权重允许垃圾邮件攻击
    • 可变成本操作的固定权重导致DoS
    • 必须使用基准测试框架,绑定所有输入参数
  4. 先验证,后写入 ⚠️ 高(v0.9.25之前)

    • 验证前的存储写入在错误时持久化(v0.9.25之前)
    • 模式:验证 → 写入 → 发出事件
    • 升级到v0.9.25+或使用手动#[transactional]
  5. 无签名交易验证 ⚠️ 高

    • 不足的验证允许垃圾邮件/重放攻击
    • 优先使用签名交易
    • 如果无签名:验证参数、重放保护、验证来源
  6. 坏随机性 ⚠️ 中

    • pallet_randomness_collective_flip易受合谋攻击
    • 必须使用BABE随机性(pallet_babe::RandomnessFromOneEpochAgo
    • 使用random(subject)而不是random_seed()
  7. 坏来源 ⚠️ 关键

    • ensure_signed允许任何用户进行特权操作
    • 必须使用ensure_root或自定义来源(ForceOrigin、AdminOrigin)
    • 来源类型必须在runtime中正确配置

有关完整的漏洞模式代码示例,请参见VULNERABILITY_PATTERNS.md


6. 扫描工作流

步骤1:平台识别

  1. 验证Substrate/FRAME框架使用
  2. 检查Substrate版本(v0.9.25+具有事务性存储)
  3. 定位pallet实现(pallets/*/lib.rs
  4. 识别runtime配置(runtime/lib.rs

步骤2:可调度分析

对于每个#[pallet::call]函数:

  • [ ] 算术:使用检查/饱和操作?
  • [ ] Panic:无unwrap/expect/索引?
  • [ ] 权重:与成本成比例,输入有界?
  • [ ] 来源:适当的验证级别?
  • [ ] 验证:所有检查在存储写入前?

步骤3:Panic扫描

# 搜索易panic的模式
rg "unwrap\(\)" pallets/
rg "expect\(" pallets/
rg "\[.*\]" pallets/  # 数组索引
rg " as u\d+" pallets/  # 类型转换
rg "\.unwrap_or" pallets/

步骤4:算术安全检查

# 查找直接算术
rg " \+ |\+=| - |-=| \* |\*=| / |/=" pallets/

# 应该找到检查/饱和替代方案
rg "checked_add|checked_sub|checked_mul|checked_div" pallets/
rg "saturating_add|saturating_sub|saturating_mul" pallets/

步骤5:权重分析

  • [ ] 运行基准测试:cargo test --features runtime-benchmarks
  • [ ] 验证权重匹配计算成本
  • [ ] 检查有界的输入参数
  • [ ] 审查权重计算函数

步骤6:来源和权限审查

# 查找特权操作
rg "ensure_signed" pallets/ | grep -E "pause|emergency|admin|force|sudo"

# 应该使用ensure_root或自定义来源
rg "ensure_root|ForceOrigin|AdminOrigin" pallets/

步骤7:测试审查

  • [ ] 单元测试覆盖所有可调度
  • [ ] 模糊测试用于panic条件
  • [ ] 基准测试用于权重计算
  • [ ] try-runtime测试用于迁移

7. 优先级指南

关键(需立即修复)

  • 算术溢出(代币创建、余额操作)
  • Panic DoS(节点崩溃风险)
  • 坏来源(未授权特权操作)

高(发布前修复)

  • 不正确的权重(通过垃圾邮件的DoS)
  • 先验证违规(状态损坏,v0.9.25之前)
  • 无签名验证问题(垃圾邮件、重放攻击)

中(审计中处理)

  • 坏随机性(操纵可能但影响有限)

8. 测试推荐

模糊测试

// 使用test-fuzz进行基于属性的测试
#[cfg(test)]
mod tests {
    use test_fuzz::test_fuzz;

    #[test_fuzz]
    fn fuzz_transfer(from: AccountId, to: AccountId, amount: u128) {
        // 应该永不panic
        let _ = Pallet::transfer(from, to, amount);
    }

    #[test_fuzz]
    fn fuzz_no_panics(call: Call) {
        // 无可调度应该panic
        let _ = call.dispatch(origin);
    }
}

基准测试

# 运行基准测试以生成权重
cargo build --release --features runtime-benchmarks
./target/release/node benchmark pallet \
    --chain dev \
    --pallet pallet_example \
    --extrinsic "*" \
    --steps 50 \
    --repeat 20

try-runtime

# 测试runtime升级
cargo build --release --features try-runtime
try-runtime --runtime ./target/release/wbuild/runtime.wasm \
    on-runtime-upgrade live --uri wss://rpc.polkadot.io

9. 附加资源


10. 快速参考清单

完成Substrate pallet审计前:

算术安全(关键)

  • [ ] 无可调度中直接的+-*/操作符
  • [ ] 所有算术使用checked_*saturating_*
  • [ ] 类型转换使用try_into()和错误处理

Panic预防(关键)

  • [ ] 无可调度中的unwrap()expect()
  • [ ] 无边界检查的直接数组/切片索引
  • [ ] 所有用户输入用ensure!验证
  • [ ] 除法操作检查零除数

权重和DoS(关键)

  • [ ] 权重与计算成本成比例
  • [ ] 输入参数有最大界限
  • [ ] 使用基准测试确定权重
  • [ ] 无免费(零权重)昂贵操作

访问控制(关键)

  • [ ] 特权操作使用ensure_root或自定义来源
  • [ ] ensure_signed仅用于用户级操作
  • [ ] 来源类型在runtime中正确配置
  • [ ] Sudo pallet在生产前移除

存储安全(高)

  • [ ] 使用Substrate v0.9.25+或手动#[transactional]
  • [ ] 验证在存储写入前
  • [ ] 事件在成功操作后发出

其他(中)

  • [ ] 无签名交易如果可能使用签名替代
  • [ ] 如果无签名:适当验证、重放保护、身份验证
  • [ ] 使用BABE随机性(不是RandomnessCollectiveFlip)
  • [ ] 随机性使用random(subject)而不是random_seed()

测试

  • [ ] 所有可调度的单元测试
  • [ ] 模糊测试以查找panic
  • [ ] 基准测试生成和验证
  • [ ] try-runtime测试用于迁移