
rust-security-review
by tomverelst
SKILL.md
name: rust-security-review description: | Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment/sensitive features in Rust. Provides a comprehensive security checklist and patterns using idiomatic crates.
Rust Security Review
This skill ensures all Rust code follows security best practices, leveraging the language's type safety while identifying potential logic-level vulnerabilities.
When to Activate
- Implementing authentication or authorization (JWT, session cookies)
- Handling user input via
serdeor public API endpoints - Working with secrets, credentials, or
.envfiles - Interacting with databases using
sqlx. - Implementing payment features or handling sensitive PII
- Integrating third-party crates or APIs
Security Checklist
1. Secrets Management
❌ NEVER Do This
// Hardcoded secret - will be compiled into the binary
const API_KEY: &str = "sk-proj-xxxxx";
✅ ALWAYS Do This
Use dotenvy for loading and envy for type-safe deserialization. Use the secrecy crate to prevent accidental logging.
use serde::Deserialize;
use secrecy::{Secret, ExposeSecret};
#[derive(Deserialize)]
struct Config {
database_url: Secret<String>,
api_key: Secret<String>,
}
fn main() {
dotenvy::dotenv().ok();
let config = envy::from_env::<Config>().expect("Missing env vars");
// Access safely: config.api_key.expose_secret()
}
Verification Steps
- No hardcoded keys in source code or
Cargo.toml. -
.envadded to.gitignore. - Sensitive strings wrapped in
secrecy::Secret. - CI/CD secrets injected via environment, not files.
2. Input Validation
Validate at the Serialization Boundary
Use the validator crate alongside serde to enforce business logic on input.
use serde::Deserialize;
use validator::Validate;
#[derive(Deserialize, Validate)]
struct SignupRequest {
#[validate(email)]
email: String,
#[validate(length(min = 8))]
password: String,
#[validate(range(min = 18, max = 120))]
age: u16,
}
// In an Axum handler
async fn register(axum::Json(payload): axum::Json<SignupRequest>) -> impl IntoResponse {
if let Err(e) = payload.validate() {
return (StatusCode::BAD_REQUEST, format!("Validation error: {}", e));
}
// Proceed...
}
Verification Steps
- All public structs implement
Validate. - String length limits enforced (prevent memory exhaustion/ReDoS).
- Numeric bounds checked (prevent overflow/logic errors).
- Whitelist validation for enums and fixed strings.
3. SQL Injection Prevention
❌ NEVER Construct SQL with String Formatting
// DANGEROUS: SQL Injection vulnerability
let query = format!("SELECT * FROM users WHERE email = '{}'", user_email);
✅ ALWAYS Use Parameterized Queries
sqlx provides compile-time checked queries that are inherently safe.
// Safe: Parameters are bound via the database protocol
let user = sqlx::query!(
"SELECT id, name FROM users WHERE email = $1",
user_email
)
.fetch_optional(&pool)
.await?;
Verification Steps
- No
format!orconcat!used to build SQL strings. -
sqlx::query!orsqlx::query_as!macros used for compile-time safety. - Database user has minimal required permissions.
4. Authentication & Authorization
Cookie Security
use axum_extra::extract::cookie::{Cookie, SameSite};
// Set secure, httpOnly cookies
let cookie = Cookie::build(("session", token))
.path("/")
.http_only(true)
.secure(true)
.same_site(SameSite::Strict)
.finish();
Password Hashing
use argon2::{
password_hash::{rand_core::OsRng, PasswordHasher, SaltString},
Argon2
};
// Use Argon2id for hashing
let salt = SaltString::generate(&mut OsRng);
let password_hash = Argon2::default()
.hash_password(password.as_bytes(), &salt)?
.to_string();
Verification Steps
- Passwords hashed with
Argon2idorscrypt. - Cookies are
HttpOnly,Secure, andSameSite=Strict/Lax. - Authorization checks performed at the handler level.
- JWTs (if used) have short expiration and validated signatures.
5. XSS Prevention
Sanitize User-Provided HTML
Use ammonia to clean any HTML intended for rendering.
let unsafe_html = "<img src=x onerror=alert(1)><b>Hello</b>";
let clean_html = ammonia::clean(unsafe_html);
// Result: "<b>Hello</b>"
Verification Steps
- User-provided strings sanitized before being rendered as HTML.
- Content Security Policy (CSP) headers implemented.
- Templates (Tera/Askama) set to auto-escape by default.
6. Rate Limiting
API Throttling
Use tower-governor (for Axum) or governor to prevent brute force.
let governor_conf = Box::new(
GovernorConfigBuilder::default()
.per_second(2)
.burst_size(5)
.finish()
.unwrap(),
);
let app = Router::new()
.route("/api/login", post(login))
.layer(GovernorLayer { config: &governor_conf });
Verification Steps
- Rate limiting applied to all auth/sensitive endpoints.
- Stricter limits on heavy database queries.
7. Blockchain (Solana/Anchor)
Arithmetic Safety
// ❌ WRONG: Potential overflow
let total = a + b;
// ✅ CORRECT: Checked math
let total = a.checked_add(b).ok_or(error!(ErrorCode::Overflow))?;
Signer and Ownership Checks
// Anchor enforces this via attributes
#[derive(Accounts)]
pub struct UpdateConfig<'info> {
#[account(mut, has_one = admin)]
pub config: Account<'info, GlobalConfig>,
pub admin: Signer<'info>, // Must sign the transaction
}
Verification Steps
- All arithmetic uses
checked_,saturating_, orsafe_methods. - Signer checks verified for all authority accounts.
- Account ownership and discriminators verified.
8. Logging and Errors
❌ NEVER Log PII or Secrets
// DANGEROUS: Logs the password
error!("Failed login for {} with password {}", email, password);
✅ ALWAYS Redact Sensitive Info
error!("Failed login attempt for email: {}", email);
// Detailed error only in internal tracing spans
Verification Steps
- No PII (emails, names, tokens) in standard logs.
- Generic error messages returned to the user (no stack traces).
- Internal errors logged with enough context for debugging.
9. Dependency Security
Audit Crates
# Check for vulnerabilities in dependencies
cargo audit
# Deny crates with specific licenses or known issues
cargo deny check
Verification Steps
-
Cargo.lockis committed to Git. -
cargo auditruns in CI/CD. - Minimal use of
unsafecode; allunsafeblocks reviewed.
Pre-Deployment Checklist
- Environment: No
.envfiles in production; use platform secrets. - Audit:
cargo auditpassed with zero vulnerabilities. - Overflows: Compiled with overflow checks (enabled by default in dev, use
checked_math for prod). - Headers: HSTS, CSP, and X-Frame-Options configured.
- Database: RLS (if using Postgres) or minimal user roles set.
- Errors: User-facing errors are generic; logs are sanitized.
Remember: In Rust, memory safety is guaranteed, but logic safety is your responsibility. Always assume user input is malicious and that environment variables are missing.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon