Instruction file imported from hasip-timurtas/solsec (
.cursor/rules/rules.mdc). Copyright stays with the author.
description: globs: ** alwaysApply: false
file_patterns:
- "**"
Project Rules and Documentation
Project Overview
solsec (Solana Smart Contract Security Toolkit) is a comprehensive Rust-based CLI tool for analyzing Solana smart contracts for security vulnerabilities. The project includes static analysis, fuzz testing, reporting capabilities, a plugin system, and an optional React-based UI.
Project Structure
solana-smart-contract-security-toolkit/
├── src/
│ ├── main.rs # CLI entry point
│ ├── cli.rs # Command-line interface handling
│ ├── analyzer.rs # Static analysis engine with built-in rules
│ ├── fuzz.rs # Fuzzing engine with IDL integration
│ ├── report.rs # Multi-format report generation
│ └── plugin.rs # Plugin system and rule traits
├── examples/ # Security vulnerability examples
│ ├── integer_overflow/ # Integer overflow vulnerabilities
│ ├── missing_signer_check/ # Missing authorization examples
│ ├── unchecked_account/ # Unsafe account access patterns
│ ├── reentrancy/ # Reentrancy vulnerability examples
│ └── README.md # Comprehensive examples documentation
├── ui/ # Optional React TypeScript UI
│ ├── src/
│ ├── package.json
│ └── vite.config.ts
├── .github/workflows/ci.yml # GitHub Actions CI/CD
├── .git/hooks/pre-commit # Native git hook for code quality
├── Cargo.toml
├── README.md
└── rules.md # This file
Core Architecture
CLI Commands
solsec scan- Static analysis of Solana programs (now generates JSON & HTML by default!)solsec fuzz- Automated fuzz testing with IDL generationsolsec plugin- Manage security rule plugins
Built-in Security Rules
The analyzer includes 4 core security rules:
integer_overflow(Medium) - Detects potential integer overflow vulnerabilitiesmissing_signer_check(High) - Identifies missing signer validationunchecked_account(Critical) - Finds accounts used without proper validationreentrancy(High) - Detects potential reentrancy vulnerabilities
Analyzer Improvements
Path Validation & Error Handling:
- File Existence Checking: Validates paths exist before analysis
- File Type Validation: Warns about non-Rust files
- Directory Analysis: Counts and reports Rust files found
- Proper Error Messages: Clear, actionable feedback instead of misleading "0 issues found"
- Colored Error Logging: ERROR messages appear in red with timestamps
- Exit Codes: Returns proper exit codes for different error conditions
Examples:
# Before: misleading output
solsec scan nonexistent.rs → "Found 0 issues"
# After: clear error messaging
solsec scan nonexistent.rs → "[ERROR] Path does not exist: nonexistent.rs" + exit code 1
solsec scan file.py → "[WARN] File is not a Rust source file (.rs): file.py"
solsec scan empty_dir/ → "[WARN] No Rust source files (.rs) found in directory: empty_dir"
Plugin System
- Rule Trait: All security rules implement the
Ruletrait - Plugin Interface: FFI-safe plugin loading with
#[no_mangle]functions - Extensibility: Custom rules can be loaded as dynamic libraries
Code Quality Standards
Clippy Configuration
CRITICAL: The project uses cargo clippy --all-targets --all-features -- -D warnings
This means ALL clippy warnings are treated as errors. The following practices MUST be followed:
Fixed Clippy Issues and Best Practices
-
Use
is_some_and()instead ofmap_or(false, |x| condition)// ❌ Bad if path.extension().map_or(false, |ext| ext == "rs") { // ✅ Good if path.extension().is_some_and(|ext| ext == "rs") { -
Move regex compilation outside loops
// ❌ Bad - creates regex in every iteration for line in lines { if Regex::new(r"pattern").unwrap().is_match(line) { // ✅ Good - compile once, use many times let regex = Regex::new(r"pattern")?; for line in lines { if regex.is_match(line) { -
Remove unnecessary borrows in function calls
// ❌ Bad Command::new("cargo").args(&["test", "arg"]) // ✅ Good Command::new("cargo").args(["test", "arg"]) -
Use iterator methods properly
// ❌ Bad - unnecessary enumerate for (_idx, item) in items.iter().enumerate() { // ✅ Good for item in items.iter() { -
Handle dead code properly
- Don't use
#[allow(dead_code)]as first resort - Actually use the code by integrating it into the system
- Only allow dead code for FFI interfaces and public APIs meant for external use
- Don't use
Code Integration Examples
When fixing dead code warnings, integrate functionality:
// Example: Using rule_settings field properly
for rule in &self.rules {
let _rule_config = self.config.rule_settings.get(rule.name());
// Use rule-specific configuration
}
// Example: Using overflow_patterns field
if self.overflow_patterns.iter().any(|pattern| pattern.is_match(line)) {
continue; // Skip already safe operations
}
Development Workflow
Git Hooks - Native Approach
PHILOSOPHY: Use native git hooks, NOT external frameworks.
Why native hooks?
- ✅ Zero dependencies (no Python, no external packages)
- ✅ Built into Git
- ✅ Simple shell script
- ✅ Project-specific
- ✅ Easy to debug and modify
Pre-commit Hook Location: .git/hooks/pre-commit
What it does:
- Format code with
cargo fmt --all - Run linting with
cargo clippy --all-targets --all-features -- -D warnings - Validate build with
cargo check --all-targets - Auto-add formatted changes to commit
Setup for new developers: The hook exists in .git/hooks/pre-commit and is executable.
Rejected Approaches
❌ Custom Makefiles: Too much maintenance, platform-specific issues ❌ Pre-commit framework: External Python dependency, overcomplicated for Rust projects ❌ Custom shell scripts: Unnecessary abstraction
Project Metadata
Author and Repository
- Author: Hasip Timurtas
- Repository:
https://github.com/hasip-timurtas/solsec - License: MIT
Version Management
- Cargo.toml version: 0.1.2
- Rust edition: 2021
- MSRV: Not specified (use latest stable)
UI Component (Optional)
Technology Stack
- Framework: React 18 with TypeScript
- Bundler: Vite
- Styling: Tailwind CSS
- Package Manager: Bun (preferred over npm/yarn)
UI Architecture
- Main App:
ui/src/App.tsx- Dashboard for security analysis results - Styling: Tailwind CSS for responsive, modern UI
- Build: Vite for fast development and optimized builds
UI Configuration Files
ui/
├── postcss.config.js # PostCSS configuration for Tailwind
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration (single file, not split)
└── vite.config.ts # Vite bundler configuration
IMPORTANT: Use single tsconfig.json, avoid tsconfig.node.json for simplicity.
CI/CD Pipeline
GitHub Actions
Located in .github/workflows/ci.yml
Pipeline steps:
- Checkout code
- Setup Rust toolchain
- Cache dependencies
- Format check:
cargo fmt --all -- --check - Linting:
cargo clippy --all-targets --all-features -- -D warnings - Tests:
cargo test - Build:
cargo build --release - UI build: Build React app with Bun
CI Requirements
- All clippy warnings must be fixed (not suppressed)
- Code must be formatted with rustfmt
- All tests must pass
- Project must build successfully
Security Analysis Engine
Analyzer Configuration
File: scsec.toml.example
enabled_rules = [
"integer_overflow",
"missing_signer_check",
"unchecked_account",
"reentrancy"
]
disabled_rules = []
[rule_settings]
[rule_settings.integer_overflow]
ignore_patterns = ["test_*", "mock_*"]
Rule Implementation Guidelines
When implementing new security rules:
-
Implement the
Ruletrait:impl Rule for MyRule { fn name(&self) -> &str { "my_rule" } fn description(&self) -> &str { "Description" } fn check(&self, content: &str, file_path: &Path) -> Result<Vec<RuleResult>> { // Implementation } } -
Use proper severity levels:
Severity::Low- Style issues, minor improvementsSeverity::Medium- Potential issues, should be reviewedSeverity::High- Likely security issuesSeverity::Critical- Definite security vulnerabilities
-
Provide actionable suggestions:
RuleResult { severity: Severity::Medium, message: "Clear description of the issue".to_string(), suggestion: Some("Specific action to fix".to_string()), code_snippet: Some(line.trim().to_string()), // ... }
Fuzzing Engine
IDL Integration
The fuzzing engine automatically:
- Discovers IDL files in common locations (
target/idl/,idl/, project root) - Generates fuzz targets from instruction definitions
- Creates harness code for each instruction
- Integrates with cargo-fuzz for execution
Fuzz Target Generation
For each instruction in an IDL:
- Creates a target named
fuzz_instruction_{name} - Generates harness with
Arbitraryderive for input fuzzing - Includes TODO comments for manual implementation
Report Generation
Supported Formats
- JSON - Machine-readable for CI/CD integration
- HTML - Beautiful, responsive reports with styling
- Markdown - Developer-friendly for documentation
- CSV - Data analysis and spreadsheet import
Report Structure
AnalysisResult {
rule_name: String,
severity: String,
message: String,
file_path: String,
line_number: Option<usize>,
column: Option<usize>,
code_snippet: Option<String>,
suggestion: Option<String>,
}
Development Best Practices
Memory Safety
- Use
anyhow::Resultfor error handling - Avoid
unwrap()in production code - use proper error propagation - Use
std::path::PathBuffor file paths - avoid string manipulation
Performance
- Compile regexes once - store in struct fields, not in loops
- Use
walkdirfor directory traversal - handles symlinks and permissions - Cache analysis results where possible
Code Organization
- Keep commands in
cli.rs- separate from business logic - Put analysis logic in
analyzer.rs- core security rule engine - Isolate plugin system in
plugin.rs- FFI and dynamic loading - Separate reporting in
report.rs- output format handling
Testing
- Unit tests for each rule - test positive and negative cases
- Integration tests for CLI - test command-line interface
- Mock file systems - use
tempfilecrate for temporary directories
Common Pitfalls and Solutions
1. Clippy Warnings
Problem: CI fails with clippy warnings
Solution: Fix warnings properly, don't suppress with #[allow]
2. Dead Code
Problem: Unused code triggers warnings Solution: Integrate code into system or remove if truly unnecessary
3. FFI Safety
Problem: Plugin interface not FFI-safe
Solution: Use #[allow(improper_ctypes_definitions)] for plugin boundaries only
4. File Path Handling
Problem: Cross-platform path issues
Solution: Always use std::path::Path and PathBuf, never string concatenation
5. Regex Performance
Problem: Slow analysis due to regex compilation in loops Solution: Compile regexes once, store in struct fields
External Dependencies
Core Dependencies
clap- Command-line argument parsingtokio- Async runtime for concurrent analysisserde- Serialization for configuration and outputanyhow- Error handlinglog- Logging frameworkwalkdir- Directory traversalregex- Pattern matching for security ruleshandlebars- HTML report templating
Development Dependencies
tempfile- Temporary files for testingpretty_assertions- Better test failure output
Future Considerations
Extensibility
- Plugin system allows external security rules
- Configuration system supports rule customization
- Report formats can be extended with new templates
Performance
- Parallel analysis using Tokio for multiple files
- Incremental analysis - only analyze changed files
- Caching of analysis results for large codebases
Integration
- IDE plugins - Language Server Protocol support
- GitHub Actions marketplace - Pre-built action
- VS Code extension - Real-time security analysis
Examples Documentation
Vulnerability Examples
The examples/ directory contains comprehensive demonstrations of security vulnerabilities:
Structure:
- 8 Rust files (4 vulnerability types × 2 versions each)
- Each vulnerability has
vulnerable.rsandsecure.rsversions - Comprehensive README with learning objectives and usage instructions
Testing Results:
solsec scan examples/integer_overflow/vulnerable.rs # 5 issues
solsec scan examples/missing_signer_check/vulnerable.rs # 5 issues
solsec scan examples/unchecked_account/vulnerable.rs # 6 issues
solsec scan examples/reentrancy/vulnerable.rs # 2 issues
solsec scan examples/ # 26 total issues
Educational Value:
- Side-by-side comparison of vulnerable vs secure patterns
- Real-world Solana/Anchor code examples
- Clear comments explaining security issues
- Regression testing for analyzer functionality
Troubleshooting
Common Issues
-
Clippy fails in CI
- Check all warnings with
cargo clippy --all-targets --all-features -- -D warnings - Fix issues, don't suppress them
- Check all warnings with
-
Pre-commit hook not working
- Verify
.git/hooks/pre-commitexists and is executable - Test manually:
.git/hooks/pre-commit
- Verify
-
"Found 0 issues" on non-existent files
- ✅ FIXED: Now shows proper error messages with colored output
- File existence validated before analysis
- Clear warnings for wrong file types or empty directories
-
UI not loading styles
- Ensure
postcss.config.jsexists for Tailwind CSS processing - Check Vite configuration includes PostCSS
- Ensure
-
Plugin loading fails
- Verify dynamic library is compiled with correct crate type:
cdylib - Check FFI function signatures match expected interface
- Verify dynamic library is compiled with correct crate type:
Debugging Tips
- Use
RUST_LOG=debugfor detailed analysis output - Check file permissions for git hooks and plugins
- Verify configuration syntax with
scsec scan --config path/to/config.toml - Test individual rules by enabling only specific rules in configuration
- Use examples for validation: Test analyzer behavior with known vulnerable/secure code
This document serves as the comprehensive guide for understanding and contributing to the scsec project. All decisions documented here were made through practical implementation and testing, prioritizing simplicity, reliability, and maintainability over complexity.