| name | substrate-vulnerability-scanner |
| description | Scans Substrate/Polkadot pallets for 7 critical vulnerabilities including arithmetic overflow, panic DoS, incorrect weights, and bad origin checks. Use when auditing Substrate runtimes or FRAME pallets. |
Substrate Vulnerability Scanner
1. Purpose
Systematically scan Substrate runtime modules (pallets) for platform-specific security vulnerabilities that can cause node crashes, DoS attacks, or unauthorized access. This skill encodes 7 critical vulnerability patterns unique to Substrate/FRAME-based chains.
2. When to Use This Skill
- Auditing custom Substrate pallets
- Reviewing FRAME runtime code
- Pre-launch security assessment of Substrate chains (Polkadot parachains, standalone chains)
- Validating dispatchable extrinsic functions
- Reviewing weight calculation functions
- Assessing unsigned transaction validation logic
3. Platform Detection
File Extensions & Indicators
Language/Framework Markers
#[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]
Project Structure
pallets/*/lib.rs - Pallet implementations
runtime/lib.rs - Runtime configuration
benchmarking.rs - Weight benchmarks
Cargo.toml with frame-* dependencies
Tool Support
- cargo-fuzz: Fuzz testing for Rust
- test-fuzz: Property-based testing framework
- benchmarking framework: Built-in weight calculation
- try-runtime: Runtime migration testing
4. How This Skill Works
When invoked, I will:
- Search your codebase for Substrate pallets
- Analyze each pallet for the 7 vulnerability patterns
- Report findings with file references and severity
- Provide fixes for each identified issue
- Check weight calculations and origin validation
5. Vulnerability Patterns (7 Critical Patterns)
I check for 7 critical vulnerability patterns unique to Substrate/FRAME. For detailed detection patterns, code examples, mitigations, and testing strategies, see VULNERABILITY_PATTERNS.md.
Pattern Summary:
-
Arithmetic Overflow ⚠️ CRITICAL
- Direct
+, -, *, / operators wrap in release mode
- Must use
checked_* or saturating_* methods
- Affects balance/token calculations, reward/fee math
-
Don't Panic ⚠️ CRITICAL - DoS
- Panics cause node to stop processing blocks
- No
unwrap(), expect(), array indexing without bounds check
- All user input must be validated with
ensure!
-
Weights and Fees ⚠️ CRITICAL - DoS
- Incorrect weights allow spam attacks
- Fixed weights for variable-cost operations enable DoS
- Must use benchmarking framework, bound all input parameters
-
Verify First, Write Last ⚠️ HIGH (Pre-v0.9.25)
- Storage writes before validation persist on error (pre-v0.9.25)
- Pattern: validate → write → emit event
- Upgrade to v0.9.25+ or use manual
#[transactional]
-
Unsigned Transaction Validation ⚠️ HIGH
- Insufficient validation allows spam/replay attacks
- Prefer signed transactions
- If unsigned: validate parameters, replay protection, authenticate source
-
Bad Randomness ⚠️ MEDIUM
pallet_randomness_collective_flip vulnerable to collusion
- Must use BABE randomness (
pallet_babe::RandomnessFromOneEpochAgo)
- Use
random(subject) not random_seed()
-
Bad Origin ⚠️ CRITICAL
ensure_signed allows any user for privileged operations
- Must use
ensure_root or custom origins (ForceOrigin, AdminOrigin)
- Origin types must be properly configured in runtime
For complete vulnerability patterns with code examples, see VULNERABILITY_PATTERNS.md.
6. Scanning Workflow
Step 1: Platform Identification
- Verify Substrate/FRAME framework usage
- Check Substrate version (v0.9.25+ has transactional storage)
- Locate pallet implementations (
pallets/*/lib.rs)
- Identify runtime configuration (
runtime/lib.rs)
Step 2: Dispatchable Analysis
For each #[pallet::call] function:
Step 3: Panic Sweep
rg "unwrap\(\)" pallets/
rg "expect\(" pallets/
rg "\[.*\]" pallets/
rg " as u\d+" pallets/
rg "\.unwrap_or" pallets/
Step 4: Arithmetic Safety Check
rg " \+ |\+=| - |-=| \* |\*=| / |/=" pallets/
rg "checked_add|checked_sub|checked_mul|checked_div" pallets/
rg "saturating_add|saturating_sub|saturating_mul" pallets/
Step 5: Weight Analysis
Step 6: Origin & Privilege Review
rg "ensure_signed" pallets/ | grep -E "pause|emergency|admin|force|sudo"
rg "ensure_root|ForceOrigin|AdminOrigin" pallets/
Step 7: Testing Review
7. Priority Guidelines
Critical (Immediate Fix Required)
- Arithmetic overflow (token creation, balance manipulation)
- Panic DoS (node crash risk)
- Bad origin (unauthorized privileged operations)
High (Fix Before Launch)
- Incorrect weights (DoS via spam)
- Verify-first violations (state corruption, pre-v0.9.25)
- Unsigned validation issues (spam, replay attacks)
Medium (Address in Audit)
- Bad randomness (manipulation possible but limited impact)
8. Testing Recommendations
Fuzz Testing
#[cfg(test)]
mod tests {
use test_fuzz::test_fuzz;
#[test_fuzz]
fn fuzz_transfer(from: AccountId, to: AccountId, amount: u128) {
let _ = Pallet::transfer(from, to, amount);
}
#[test_fuzz]
fn fuzz_no_panics(call: Call) {
let _ = call.dispatch(origin);
}
}
Benchmarking
cargo build --release --features runtime-benchmarks
./target/release/node benchmark pallet \
--chain dev \
--pallet pallet_example \
--extrinsic "*" \
--steps 50 \
--repeat 20
try-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. Additional Resources
10. Quick Reference Checklist
Before completing Substrate pallet audit:
Arithmetic Safety (CRITICAL):
Panic Prevention (CRITICAL):
Weights & DoS (CRITICAL):
Access Control (CRITICAL):
Storage Safety (HIGH):
Other (MEDIUM):
Testing: