Rust security
Skill Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack/plugins/devtools-pack/skills/rust-security
When to activate: Rust security, unsafe code, input validation, secret handling, cryptography, supply chain, audit, injection preventionFrom its SKILL.md
npx -y skills add Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack --skill rust-securityAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.4 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it
Rust Security Patterns
Safe Defaults
Rust's type system prevents many vulnerability classes in safe code:
- Memory safety: no buffer overflows, use-after-free, or dangling pointers
- No null pointer dereferences:
Option<T>forces explicit handling - Thread safety:
Send/Syncprevent data races at compile time - Integer overflow: caught in debug; use
checked_*/saturating_*in release
fn safe_multiply(a: u64, b: u64) -> Option<u64> {
a.checked_mul(b)
}
Handling Secrets
[dependencies]
secrecy = "0.10"
zeroize = "1"
subtle = "2"
use secrecy::{Secret, ExposeSecret};
struct Credentials {
username: String,
password: Secret<String>, // will not appear in Debug output
}
fn authenticate(creds: &Credentials, input: &str) -> bool {
let pwd = creds.password.expose_secret();
// Constant-time comparison prevents timing attacks
use subtle::ConstantTimeEq;
pwd.as_bytes().ct_eq(input.as_bytes()).into()
}
Input Validation
use validator::Validate;
#[derive(Debug, Validate, serde::Deserialize)]
struct CreateUserRequest {
#[validate(length(min = 2, max = 64))]
name: String,
#[validate(email)]
email: String,
#[validate(length(min = 12))]
password: String,
}
async fn create_user(Json(req): Json<CreateUserRequest>) -> Result<Json<User>, ApiError> {
req.validate().map_err(|e| ApiError::BadRequest(e.to_string()))?;
todo!()
}
SQL Injection Prevention
Always use parameterized queries — never string-interpolate user input into SQL.
// NEVER DO THIS
let query = format!("SELECT * FROM users WHERE name = '{}'", user_input);
// ALWAYS DO THIS (sqlx)
let user = sqlx::query_as!(User, "SELECT * FROM users WHERE name = $1", user_input)
.fetch_optional(pool).await?;
Path Traversal Prevention
fn safe_join(base: &std::path::Path, user_input: &str) -> anyhow::Result<std::path::PathBuf> {
let clean = user_input.trim_start_matches(['/', '.', '\\']);
let candidate = base.join(clean);
let canonical = candidate.canonicalize()?;
anyhow::ensure!(
canonical.starts_with(base),
"path traversal attempt: {:?} outside {:?}", canonical, base
);
Ok(canonical)
}
Password Hashing
[dependencies]
argon2 = "0.5"
rand = "0.8"
use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
use argon2::password_hash::{rand_core::OsRng, SaltString};
fn hash_password(password: &str) -> anyhow::Result<String> {
let salt = SaltString::generate(&mut OsRng);
Ok(Argon2::default().hash_password(password.as_bytes(), &salt)?.to_string())
}
fn verify_password(password: &str, hash: &str) -> anyhow::Result<bool> {
let parsed = PasswordHash::new(hash)?;
Ok(Argon2::default().verify_password(password.as_bytes(), &parsed).is_ok())
}
Secure Random Tokens
use rand::Rng;
fn generate_token() -> String {
let bytes: Vec<u8> = (0..32).map(|_| rand::thread_rng().gen()).collect();
hex::encode(bytes)
}
Supply Chain Security
cargo install cargo-audit && cargo audit # known CVEs
cargo install cargo-deny # license/ban/source policies
cargo install cargo-outdated && cargo outdated
unsafe Code Guidelines
unsafe fn dangerous(ptr: *const u8, len: usize) -> &'static [u8] {
// SAFETY:
// - `ptr` is valid for `len` bytes (caller's responsibility)
// - the lifetime is correct (caller ensures data outlives 'static)
// - no mutable aliasing exists (caller's guarantee)
std::slice::from_raw_parts(ptr, len)
}
Common Anti-Patterns
- Logging secrets or PII — redact before logging; use
secrecy::Secret unwrap()on user-controlled deserialization — handle errors explicitlymd5/sha1for passwords — useargon2,bcrypt, orscrypt- Trusting
Content-Typeheaders — validate the actual content, not the declared type - Not committing
Cargo.lockfor services — commit it for binaries/services; omit for libraries
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.