This guide covers security tools and resources for auditing and securing Stellar/Soroban smart contracts.
Security is critical for smart contract development. Stellar provides several tools and programs to help developers build secure applications.
Vulnerability detector and linter for Soroban smart contracts by CoinFabrik.
| Feature | Details |
|---|---|
| GitHub | CoinFabrik/scout-soroban |
| Type | Static analysis tool |
| Languages | Rust (Soroban contracts) |
Features:
- CLI tool for CI/CD integration
- VSCode extension for real-time feedback
- Detects common vulnerabilities
- Customizable rule sets
Installation:
# Install via cargo
cargo install scout-soroban
# Run on your project
scout-soroban /path/to/contractVSCode Extension: Search for "Scout Soroban" in the VSCode marketplace.
Detected Vulnerabilities:
- Integer overflow/underflow
- Unsafe unwrap usage
- Missing authorization checks
- Reentrancy patterns
- Uninitialized storage
- And more...
Security-audited contract examples demonstrating secure patterns.
| Feature | Details |
|---|---|
| GitHub | CoinFabrik/scout-soroban-examples |
| Use Case | Learning secure patterns, reference implementations |
Funding program for security audits of Stellar Community Fund projects.
| Feature | Details |
|---|---|
| Website | stellar.org/grants-and-funding/soroban-audit-bank |
| Eligibility | SCF-funded projects |
Features:
- Pre-negotiated audit rates
- Readiness checklist
- Multiple audit firms available
- Streamlined process for SCF projects
// Always verify caller authorization
pub fn transfer(e: &Env, from: Address, to: Address, amount: i128) {
from.require_auth(); // Critical!
// ... transfer logic
}// Use checked arithmetic
let result = amount.checked_add(fee).expect("overflow");
// Or use saturating operations for bounded values
let capped = balance.saturating_sub(withdrawal);pub fn deposit(e: &Env, amount: i128) {
// Validate inputs
if amount <= 0 {
panic!("Amount must be positive");
}
if amount > MAX_DEPOSIT {
panic!("Amount exceeds maximum");
}
// ... deposit logic
}// Check for existence before reading
let balance: i128 = e.storage()
.persistent()
.get(&key)
.unwrap_or(0); // Safe default// Update state before external calls
pub fn withdraw(e: &Env, user: Address, amount: i128) {
user.require_auth();
// 1. Check
let balance = get_balance(e, &user);
if balance < amount {
panic!("Insufficient balance");
}
// 2. Update state FIRST
set_balance(e, &user, balance - amount);
// 3. External call LAST
transfer_tokens(e, &user, amount);
}- Run Scout Soroban analysis
- All functions have proper authorization
- Integer operations are checked/saturating
- Inputs are validated
- Storage access is safe
- No hardcoded secrets
- Events emitted for important actions
- Upgrade mechanism is secure (if applicable)
- Tested on testnet extensively
- Professional security audit completed
- Multiple auditors if possible
- Bug bounty program considered
- Incident response plan in place
- Monitoring and alerting set up
| Vulnerability | Description | Prevention |
|---|---|---|
| Missing Auth | Forgetting require_auth() |
Always require auth for state changes |
| Integer Overflow | Arithmetic exceeds type bounds | Use checked/saturating math |
| Reentrancy | External calls before state updates | Update state before calls |
| Access Control | Incorrect role checks | Use OpenZeppelin access control |
| Uninitialized Storage | Reading unset values | Always provide defaults |
| Front-running | Transaction ordering attacks | Use commit-reveal patterns |