SOTA Rust (2026)
Purpose
This skill encodes the 2026 state of the art for production Rust: the idioms,
security posture, performance discipline, and CI baseline expected of an
expert Rust codebase. Baseline as of mid-2026: a recent stable Rust toolchain (verify the current
release at blog.rust-lang.org),
edition 2024 (next edition expected ~2027), tokio still 1.x. It serves two modes — BUILD (write new code to this
standard) and AUDIT (find where existing code falls short, with severity
and evidence). The detailed rules live in rules/*.md; load only the files
relevant to the task (see index below). Every rules file ends with an "Audit
checklist" of grep/clippy patterns — use those verbatim in AUDIT mode.
BUILD mode
When writing or modifying Rust code:
- Scope the work, load the rules. Pick the relevant
rules/files from the index. Touching async code? Load 04. Adding a dependency, parsing network input, or spawning an external program? Load 05. Writing anyunsafe? Load 03 — no exceptions. - Design types first. Newtypes for domain primitives, errors per
subsystem (thiserror for libs, anyhow for apps), ownership tree before
Arc<Mutex<_>>, public API minimal and borrowed (&str/&[T]params). Parse, don't validate: constructors enforce invariants. - Write to the non-negotiables (bottom of this file) without being asked.
They are defaults, not suggestions; deviations carry a written
justification at the site (e.g.
expectwith invariant message,#[allow(lint, reason = "...")]). - Wire the scaffolding with the code, not after: lints in
[lints],deny.toml+cargo denyin CI for anything deployed, Miri job if unsafe exists, nextest, MSRV declared and tested, benches for claimed-hot paths. See rules/07 §9 for the CI shape to copy. - Verify before claiming done:
cargo fmt --check,cargo clippy --all-targets --all-features -- -D warnings,cargo nextest run+cargo test --doc, andcargo docwarning-free for libraries. If you wrote unsafe:cargo +nightly miri testover it. If you claimed performance: show the benchmark. - Comment intent at decision points the next reader will question:
justified clones, cancel-safety of
select!arms, SAFETY comments, channel-capacity choices, poisoning policy.
AUDIT mode
When reviewing or auditing existing Rust:
- Recon first:
cargo metadata/workspace layout,Cargo.tomlprofiles and features, CI config,rg 'unsafe' --count-matches, dependency tree (cargo tree -d). This decides which rules files to load and where risk concentrates (network input? unsafe? async service?). - Run the audit checklists at the end of each loaded rules file — they are ordered grep/clippy hunts with pre-calibrated severities.
- Validate every finding: read the surrounding code; a grep hit is a lead, not a finding. Confirm reachability (is the unwrap on an attacker-influenced path?) before assigning severity.
- Report with the finding format below. Prefer few, true, prioritized findings over volume. Note positive observations where the code is already SOTA (prevents "fixes" that regress good decisions).
Severity conventions
| Severity | Meaning | Examples |
|---|---|---|
| Critical | Exploitable now, or UB | reachable UB, unsound safe API, SQLi/path traversal, authn bypass, unwinding across FFI, secrets in logs+repo |
| High | Exploitable under realistic conditions, or correctness loss | attacker-reachable panic/OOM (DoS), wrapped arithmetic on untrusted lengths, cancellation data loss, deadlock (block_on in async, lock across await), unbounded channels fed by network, missing dep-audit in deployed-service CI |
| Medium | Latent defect or eroded defense | missing SAFETY comments, no Miri CI on unsafe crate, swallowed errors (.ok(), filter_map(Result::ok)) uncommented, untested MSRV, non-additive features, orphaned spawned tasks |
| Low | Hygiene, idiom, maintainability | clone-to-satisfy-borrowck, index loops, missing #[non_exhaustive], missing # Errors docs, blanket #[allow] without reason |
Severity scales with reachability (attacker-controlled > user > operator > build-time) and blast radius (process death > request failure > slow).
Finding format
[SEVERITY] short title
Where: path/to/file.rs:123 (fn name / module)
What: the defect, in one or two sentences
Why: concrete consequence (exploit path, failure mode, cost)
Fix: specific change — code sketch or named pattern from rules/NN
Effort: trivial | small | medium | large
Refs: rules/NN §M; clippy lint or RUSTSEC id if applicable
Group findings by severity, Critical first. End with: checklist coverage (which rules files were applied), what was not reviewed, and quick wins (one-line fixes with outsized value).
Rules index
| File | Read this when... |
|---|---|
| rules/01-ownership-and-api-design.md | Designing structs/traits/modules/workspaces; fighting the borrow checker; deciding clone vs borrow vs Rc/Arc; newtype, typestate, builder patterns; sealed traits, coherence; comparison-trait (Eq/Ord) invariants; exhaustive matching; iterator-chain idioms |
| rules/02-errors-and-panics.md | Choosing thiserror vs anyhow/eyre; designing error enums; unwrap/expect policy and invariant messages; context discipline; panic policy for servers, FFI, and Drop (no panic in destructors); Option/Result combinator flow; not unwrapping an Option back into a sentinel (unwrap_or(-1), serde(default) on numbers) |
| rules/03-unsafe-discipline.md | Writing or reviewing ANY unsafe; SAFETY comment standards; UB catalog (aliasing, uninit, transmute, FFI lifetimes); Miri/sanitizers/loom in CI; cargo-geiger; soundness review protocol |
| rules/04-async-tokio.md | Anything async: tokio, spawn vs spawn_blocking, Send/Sync bound errors, select! and cancellation safety, JoinSet/TaskTracker, channel selection, locks across await, async traits, graceful shutdown |
| rules/05-security-supply-chain.md | Network-facing or deployed code; adding dependencies; cargo audit/deny/vet; integer overflow on untrusted input; panic-DoS; zeroize/constant-time for secrets; serde hardening (untagged enums, size limits); service-edge defaults; spawning external programs (std::process::Command — argv vs shell, the Windows .bat CVE, a dropped Child that keeps running, deadlines that don't kill, §9) |
| rules/06-performance.md | Performance work or claims: profiling (samply/perf/flamegraph, criterion/divan), allocation reduction (Cow/SmallVec/buffer reuse), accidental clones, iterator fusion, release profile (LTO, codegen-units, panic=abort), PGO |
| rules/07-tooling-ci.md | Setting up or auditing repo scaffolding: clippy policy and pedantic triage, rustfmt, nextest, MSRV declaration+testing, additive feature flags, docs.rs discipline, edition 2024 migration, CI baseline. Test strategy — suite shape, TDD, doubles, test data, flake policy — lives in sota-testing; load it for any build that writes logic. This file owns Rust runner mechanics only. |
Top-10 non-negotiables
- No
unwrap()/bareexpect()on production paths. Propagate with?+ context;expect("...")only with a message proving the invariant. An attacker-reachable panic is a DoS. (rules/02) - Every
unsafeblock has a// SAFETY:comment discharging the called API's documented preconditions, and lives behind a sound safe abstraction. Unsafe code without Miri in CI is unaudited code. (rules/03) - Libraries: thiserror enums with
#[source]chains. Applications: anyhow with.context(). Neveranyhow::Errorin a public lib API; never silently swallowed errors. (rules/02) - Never block the async runtime: no sync I/O,
std::thread::sleep, or sustained CPU insideasync fn;spawn_blockingor a compute pool. Nostd::sync::MutexGuardheld across.await. (rules/04) - Every
select!/timeout/abort path is cancellation-reviewed: futures dropped at any.await; cancel-unsafe ops don't go inselect!arms; invariants spanning awaits get drop guards. Spawned tasks are owned (JoinSet/TaskTracker), never orphaned. (rules/04) - Untrusted input gets checked arithmetic, size limits, and depth limits:
checked_*/try_intoon lengths (release mode wraps silently), body-size caps before parsing, no#[serde(untagged)]or uncappedwith_capacityon hostile data. (rules/05) - Supply chain is CI-enforced:
cargo deny/cargo auditon PRs + scheduled,Cargo.lockcommitted, new deps vetted (cargo vet or documented review), git deps pinned by rev. (rules/05) - Secrets are typed (
SecretString/Zeroizing), redacted from Debug/logs, and compared in constant time (ct_eq). Key material only from OS randomness. (rules/05) - Don't clone to satisfy the borrow checker; don't take owned params you
only read.
&str/&[T]in signatures, split borrows,mem::take; newtypes over primitive obsession; exhaustive matches (no lazy_ =>on owned enums). (rules/01) - CI gate: fmt + clippy
-D warnings(triaged pedantic) + nextest + doctests + MSRV job + feature-matrix check. Performance claims require benchmarks; release profile (LTO/codegen-units/panic strategy) is a deliberate, documented choice. (rules/06, 07)