Overview
Security testing in Rust concentrates where Rust's risks actually are. Memory safety
removes the classic C/C++ bug classes from safe code, so the portfolio tilts toward
three fronts: the supply chain (a deep, fine-grained dependency graph whose build
scripts run arbitrary code), the unsafe surface (small but load-bearing), and
the input boundary (parsers and protocols, where panics become DoS). The
scanner-heavy SAST culture of the
Java portfolio has a correspondingly smaller
role here.
Key points
- Supply chain first:
cargo audit(RustSec advisories againstCargo.lock),cargo deny(advisories + licenses + source policy as a CI gate),cargo vet(human-audit records) — mechanics in Building & releasing; this is the row every Rust CI needs. - Unsafe hygiene is auditable:
cargo geigercounts and locatesunsafeacross the dependency tree (an exposure metric, not a verdict);#![forbid(unsafe_code)]on crates that should have none turns the metric into a guarantee; miri checks the unsafe that remains for actual UB. - Fuzz the boundary: every deserializer, framing layer and file-format parser gets a cargo-fuzz target; in Rust the typical finding is a panic or resource-exhaustion path — a denial-of-service bug class, reachable from safe code, and the most common real-world Rust CVE shape alongside logic flaws.
- Panics are the forgotten attack surface:
unwrapon attacker-controlled input is a remote crash; clippy'sunwrap_used/expect_usedrestriction lints, panic = abort consequences, and load-shedding limits (web security) are the mitigations. - SAST exists, scaled to need: clippy's correctness/suspicious classes catch API-misuse patterns; semgrep has Rust rules; there is no FindSecBugs-scale ecosystem because injection-style sinks are rarer — the type system and parameterized queries by construction close most of them.
- DAST is language-agnostic: ZAP/Burp against a staging deployment work the same as ever; nothing Rust-specific to add beyond the E2E harness to drive it.
- Sanitizers still matter at the FFI edge:
-Zsanitizer=address(nightly) for mixed Rust/C binaries — memory safety promises stop atextern "C".
Details
The portfolio, one row each
| Front | Tool | Cadence |
|---|---|---|
| Known-vuln dependencies | cargo-audit / cargo-deny | Every CI run |
| Dependency trust | cargo-vet (+ lockfile discipline, --locked) |
On dependency change |
| Unsafe exposure | cargo-geiger, #![forbid(unsafe_code)] |
Audit checkpoints |
| UB in unsafe code | miri, sanitizers at FFI | CI on unsafe-bearing crates |
| Input surface | cargo-fuzz targets, proptest no-panic properties | Nightly / continuous (OSS-Fuzz) |
| Runtime posture | ZAP/Burp on staging, security headers checks | Pre-release |
Related
- Testing in Rust — strategies & tooling map — parent map.
- Building & releasing — audit/deny/vet mechanics and SBOMs.
- Property-based testing & fuzzing — the fuzzing machinery this portfolio leans on.
- Security in Rust applications — building securely, the concern this note verifies.
- Security testing in Java and in Go — the neighbouring portfolios; Go's govulncheck reachability analysis is the feature cargo-audit lacks.
- AppSec fundamentals — the SCA/SAST/DAST vocabulary these tools instantiate.