* rust-review: add Rust security review plugin Add the rust-review plugin: a comprehensive Rust security review skill with clustered finders covering memory safety, concurrency/data races, panic-induced DoS, FFI/cross-language boundaries, error handling, resource handling, async runtime, and static hygiene. Includes worker, dedup-judge, fp-judge, and planner agents, SARIF generation with rule descriptions and regression tests, deterministic cluster chunking, and Codex skills mapping. Versioned at 1.0.0 and registered in the marketplace, CODEOWNERS, and root README. * c-review: backport rust-review protocol fixes and planner chunking Port the language-agnostic fixes made while building rust-review (which was ported from c-review) back into c-review: - worker/fp-judge: force findings, coverage gate, and REPORT.md to disk via Write instead of returning content in the reply (orchestrator context-bloat hardening); add a pre-complete file-existence check. - worker: move the cache-primer block below the normal self-check and pre-work budget so a non-primer worker does not start under a global "no tool calls" rule. - planner: add --max-passes-per-worker (default 4) with deterministic split_oversized_clusters chunking; skill passes the flag and documents the chunked-subset worker rule. - scripts: add test_split.py and test_generate_sarif.py regression tests. The SARIF test caught a missing RULE_DESCRIPTIONS entry for uninitialized-data, now added. Bump c-review to 1.2.0. * c-review/rust-review: validate artifacts, index-aware SARIF, protocol cleanups - Add validate_artifacts.py (+ tests) to both plugins to check worker shard, coverage, and finding files before accepting completions. - generate_sarif.py now reads the canonical findings-index.txt when present, falling back to findings/*.md only if the index is absent. - Merge the worker step-6 verification paragraphs and drop orchestrator -internal Phase 7 / plan.json jargon in favor of worker-facing stakes. - Tighten uninitialized-read-finder guidance: primitive integers still require initialization. * rust-review/c-review: per-cluster max_passes_per_worker override Lets output-heavy clusters declare a smaller manifest-level max_passes_per_worker so each expensive pass group gets its own worker, validated by a single shared cluster_max_passes_per_worker helper and honored by split_oversized_clusters via an explicit override (0 is rejected rather than silently falling back to the global cap). rust-review opts in concurrency-locking and recursion-dos; c-review ports the capability for parity. validate_artifacts now accepts grouped or repeated --claimed-count values. * rust-review: broaden bug-class coverage with capability-gated clusters Add layout-safety, input-os-safety, and info-disclosure clusters behind new has_packed_repr / has_fs_io capability gates so packed-repr, path, and pointer-exposure passes only run where they apply, and gate unsafe-only passes behind has_unsafe to cut noise on safe crates. Extend existing clusters with new bug classes: RefCell double-borrow panics, unflushed BufWriter, string-comparison bypasses, serialize_struct mismatches, nondeterminism, in-collection key mutation, and destructor-skip cleanup leaks. Fix detector regexes that missed or over-matched real Rust (packed-field borrows, RefCell try_borrow_mut, HashMap substrings, path push, packed inner attrs, fs/path probes) and add a regression test pinning them to snippets. * fix dedup * safety-net check for REPORT.md * on-disk data -> shards reconciliation * on-disk data -> shards reconciliation - v2 * ls -> glob * memory-safety gate * path validation * fix numbers/counting * rm PACKEDREF from FFI cluster prompt, it is in layout-safety * fix unsafe-boundary count * minor fixes for prompts * do not filter unknown-severity findings, just mark them as such * fix minor behavior changes in worker * Correctness: - generate_sarif: clamp startLine >=1 (`:0` produced schema-invalid SARIF) - generate_sarif: don't drop a judged survivor with blank severity - dedup-judge: Tier-2 carry-forward so a primary can't be demoted/orphaned - dedup-judge: crash-recovery unions shards with findings/*.md (empty-shard trap) Robustness: - generate_sarif: skip frontmatter-less files; add originalUriBaseIds Contracts: - SKILL: gate dedup-judge before fp-judge (prevent concurrent-spawn race) - worker: verbatim coverage cells; sub_prompt_paths omitted-not-empty; skip_subclasses reserved; Codebase comma format * improve prompts regexes, add missing deconflictions * prompt factual fixes * fix dozen of small prompt inconsistencies and add missing sections * more prompt fixes, fix retry guard in SKILL, small fixes in agents * dozen more small fixes * final regex fixes * fixes from rust to c-review * agents cannot use write tool for reports (strange cc limitation) - bypass via bash * spawnings agents is capped to 20 - explicit handling for that * fix glob -> read (glob is blocked for agents that has also bash) * fix regex patterns to work with grep * soften output requirements - they were violated anyway * consolidated clusters are no longer chunked — one worker owns the whole cluster, builds its shared Phase-A inventory once, and runs every phase * fix judge finding counting and low-severity guidance * fix metadata * small fix for skipped findings * Carry forward guard for `also_known_as` bucket * Gracefully handle parse_frontmatter error * Extend has_ffi coverage * Broader gate for has_concurrency * Update FFI-safe layout regex to support C, C+packed, and C+u32 in unsafe-boundary and dyn-trait-ffi-finder prompts * Small refine of regex patterns * Improve regex patterns for recursive type detection to include Mutex and RwLock * rm global .codex/rust-review * backport fixes to c-review * merge changes * Backport SARIF merge-survivor + malformed-frontmatter guards to c-review, mark missing locations, fix prompt-regex test extractor, and harden planner/validator scripts across both review plugins * fix pytest * fix global gitignore, adds / and ruff_cache * small fixes from pr-review * small fixes from pr-review - 2 * fix copilot finding --------- Co-authored-by: GrosQuildu <e2.8a.95@gmail.com>
rust-review
Rust security code review plugin. Bug-class coverage comes from empirical bug-shape research across 245 memory-corruption, 177 unsound safe-API, 150 denial-of-service, and 60 thread-safety advisories in the RustSec Advisory Database (1,078 entries) and audits. Orchestration matches c-review.
Usage
Invoke with /rust-review:rust-review. The skill will prompt for:
- Threat model (
REMOTE/LOCAL_UNPRIVILEGED/BOTH) - Worker model (
haiku/sonnet/opus) - Severity filter (
all/medium/high) - Scope subpath (optional — defaults to whole repo)
Findings + SARIF are written to $(pwd)/.rust-review-results/<iso-timestamp>/.
Overview
Inputs (AskUserQuestion): threat model, scope subpath (optional), worker model, severity filter.
From these inputs the orchestrator detects Rust capability flags (has_unsafe, has_ffi, has_concurrency, has_async, has_packed_repr, has_fs_io) over the scope and selects clusters from prompts/clusters/manifest.json. Each cluster groups related bug classes anchored on a shared mental model and runs as one parallel worker.
The planner caps each non-consolidated worker at four passes, splitting larger
clusters into -1/-2/… chunks; output-heavy clusters can declare a smaller
max_passes_per_worker in the manifest (today recursion-dos runs one pass per
worker). Consolidated clusters (unsafe-boundary, concurrency-locking) are
never chunked — one worker owns the whole cluster so its shared Phase-A inventory
is built once and grounds every phase.
Always-on clusters:
- unsafe-boundary (consolidated) — Unsafe Reachability Analysis (URAPI),
transmutemisuse, pointer-cast hazards viaas(PTRCAST), raw-pointer arithmetic,#[repr(C)]layout, enum discriminant and niche validity (ENUMUB),// SAFETY:documentation rules,debug_assert!-guarded safety invariants. - panic-dos — resource exhaustion DoS (RESEXHAUST, P0),
unwrap/expecton untrusted input, arithmetic overflow, reachableunreachable!/assert!, vector OOB indexing, non-char-boundarystrslicing panics (STRSLICE), reachableRefCelldouble-borrow panics (REFCELLPANIC). - recursion-dos — stack-overflow aborts (uncatchable, distinct from panics) on recursive types: unbounded deserialization depth (
serde_yaml/toml/ron/customDeserialize), recursiveDisplay/Debug/Serializeon attacker-shaped values, implicitDropofBox<Self>-style chains. - error-handling — discarded
Results, panics insideDrop, lossyFrom/Intoandascasts, lossy UTF-8 / OS-string / path conversions (LOSSYSTR), unflushedBufWriterswallowing write errors (BUFFLUSH). - logic-correctness —
Ord/Eq/Hashinvariant violations, hostile generic trait impls, closure-panic across unsafe scaffolding, NaN/Inf edge cases, partial-match/case string comparisons (STRCMP),serialize_structfield-count mismatches (SERFIELDS), nondeterminism in replicated state (NONDET), in-collection key mutation (KEYMUT). The hostile-trait (TRAITADV) and closure-panic (CLOSUREPANIC) passes requirehas_unsafe. - static-hygiene — Cargo lint config, MSRV, deprecated APIs (
mem::uninitialized). - resource-handling — raw file-descriptor double-close and leak (RAWFD),
Drop-skipping cleanup viaprocess::exit/mem::forget(DROPSKIP). - info-disclosure — pointer/address exposure that defeats ASLR (PTREXPOSE).
Conditional clusters:
- memory-safety (
has_unsafe) — UAF via dangled raw pointer, double-free viaptr::read, invalid-free via assignment-to-uninit, uninitialized-read via prematureassume_init,Vec::set_lenwithout slot init (SETLEN), buffer overflow via safe→unsafe index propagation, union variant misread, panic-unsafe custom container drop (PANICUNWIND). The whole cluster is gated onhas_unsafe(every memory-safety bug class requiresunsafe), so it is omitted entirely for pure safe-Rust crates. - concurrency-locking (
has_concurrency, consolidated) —MutexGuarddouble-lock from lexical scope, ABBA ordering,Condvarwait without notifier, channel starvation,Once::call_oncereentrancy, signal-handler / callback reentrancy. - concurrency-data-race (
has_concurrency) — non-atomic atomic sequences,unsafe impl Syncover interior mutability, missingSend/Syncbounds, cross-process shared-memory races, unsynchronizedstatic mut(STATICMUT). The unsafe-sync-impl (UNSAFESYNC) and static-mut (STATICMUT) passes requirehas_unsafe. - ffi-cross-language (
has_ffi) —CString::as_ptrdangling, ABI mismatch,#[repr(C)]padding leak, opaque-pointer ownership confusion, FFI-owned-memory drop mismatches, Rust closures acrossextern "C"withoutcatch_unwind,dyn Traitfat pointers crossing FFI. - layout-safety (
has_packed_repr) — unaligned references to#[repr(packed)]/ wire-format struct fields (PACKEDREF). - input-os-safety (
has_fs_io) —PathBuf::joinpath traversal (PATHJOIN), filesystem TOCTOU (TOCTOU). - async-runtime (
has_async) — blocking calls in async, cancellation-unsafe.awaitsequences,tokio::select!branch bias.
Same orchestration as c-review: workers spawn foreground (one message per wave of ≤16 workers, after an optional cache primer), write markdown-with-YAML-frontmatter finding files, then a dedup-judge merges duplicates, then an fp-judge assigns fp_verdict / severity / attack_vector / exploitability. A report safety net then runs: SARIF is regenerated unconditionally, and the orchestrator writes REPORT.md itself if the fp-judge failed to.
Architecture
coordinator: write context.md → build_run_plan.py → TaskCreate × M
→ spawn primer (foreground) → spawn M workers (parallel)
→ classify Phase-7 outcomes + write findings-index.txt
→ dedup-judge → fp-judge → report safety net (SARIF + REPORT.md) → return REPORT.md
| Subagent type | Purpose | Tool set |
|---|---|---|
rust-review:rust-review-worker |
Run assigned cluster, write findings | Read, Write, Edit, Bash |
rust-review:rust-review-dedup-judge |
Merge duplicates (runs first) | Read, Write, Edit, Glob |
rust-review:rust-review-fp-judge |
FP + severity + final reports (runs second) | Read, Write, Edit, Bash |
In current Claude Code an agent granted Bash is not also granted the dedicated Glob/Grep tools (the harness expects find/grep/rg via Bash). So the worker and fp-judge search and resolve paths with Read/Bash, running the ripgrep-syntax prompt seeds through rg; only the dedup-judge — which holds no Bash — uses Glob.
Output directory layout
Default: $(pwd)/.rust-review-results/<iso-timestamp>/. Contains:
context.md— resolved threat model, severity filter, scope, capability flags, Cargo manifest statusplan.json— selected clusters + rendered worker spawn prompts (one per parallel worker)worker-prompts/— verbatim spawn prompts, one per worker (+ optionalcache-primer.txt)findings/— one markdown file per finding (<PREFIX>-NNN.mdwith YAML frontmatter)findings-index.d/— per-worker shards listing finding paths (survive an orchestrator crash)findings-index.txt— canonical sorted list of every finding file on disk (reconciled against the shards)run-summary.md— worker outcome table, retry/abort state, judge statusdedup-summary.md— Tier 1–3 merge + Tier 4 related summaryfp-summary.md— verdict counts and per-primary verdict tableREPORT.md— human-readable final report grouped by severity, filtered perseverity_filterREPORT.sarif— SARIF 2.1.0 export, idempotent (full overwrite), always written
Not for
- Pure C / C++ codebases — use
c-reviewinstead. - Smart contracts (Solana, NEAR, Ink!) — use
solana-vulnerability-scanneror the contract-specific skill. - Kernel-mode Rust without userspace allocator — coverage is incomplete; flag as advisory only.
References
- Rustonomicon — unsafe invariants
- Rust API Guidelines
Authors
- Andrea Cappa @ Aptos Labs
- Paweł Płatek @ Trail of Bits