SkillAgentSearch skills...

rust-review

Performs comprehensive Rust security review for safe/unsafe boundary issues, memory safety in unsafe blocks, concurrency hazards, panic-induced DoS, FFI safety, and async runtime mistakes

Install / Use

npx skills add trailofbits/skills --skill rust-review

Installs into whichever agent you are using.

About this skill
📄

SKILL.md

Installable skill definition

Quality Score

87/100

Category

Security

Supported Platforms

Universal

Our assessment of rust-review

rust-review scores 87/100 on our quality scale, 492nd of 774 Security skills we index.

Its SKILL.md is 43 KB long, well organised into 43 sections with 11 code examples: long enough that it reads more like full documentation than a focused instruction file, which agents can find harder to follow.

With 7,225 GitHub stars, it is one of the more widely adopted skills in the catalogue.

Substance
21/30
Structure
20/20
Description
15/15
Adoption
16/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated 4 days ago, so rust-review is actively maintained.
  • It is released under the CC-BY-SA-4.0 license; check its terms before commercial use.
  • Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

rust-review compared with similar skills

All 4 of these similar skills score higher than rust-review; compare them before choosing.

SkillScoreStarsUpdatedFormat
rust-review (this skill)by trailofbits877.2k4d agoSKILL.md
algorithmic-artby anthropics100177.9k5d agoSKILL.md
pptxby anthropics100177.9k5d agoSKILL.md
designby nextlevelbuilder100130.2k6d agoSKILL.md
ui-ux-pro-maxby nextlevelbuilder100130.2k6d agoSKILL.md

Frequently asked questions

How do I install rust-review?
Run npx skills add trailofbits/skills --skill rust-review. The install tabs above show the steps for each supported agent.
Which AI agents does rust-review work with?
It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
Is rust-review safe to use?
It is CC-BY-SA-4.0-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is rust-review still maintained?
The repository was last updated 4 days ago, so rust-review is actively maintained.

name: rust-review description: Performs comprehensive Rust security review for safe/unsafe boundary issues, memory safety in unsafe blocks, concurrency hazards, panic-induced DoS, FFI safety, and async runtime mistakes. Use when auditing Rust crates, services, or libraries — particularly those with unsafe, FFI, or concurrent code. allowed-tools: Agent AskUserQuestion SendMessage TaskCreate TaskUpdate TaskList Read Write Bash

Rust Security Review

Runs in the main conversation (invoke via /rust-review:rust-review). Orchestrator owns the Task* ledger as bookkeeping for retries; workers and judges have no Task tools. Workers and judges are named plugin subagents (rust-review:rust-review-worker, rust-review:rust-review-dedup-judge, rust-review:rust-review-fp-judge); tool sets are declared in plugins/rust-review/agents/*.md. Findings are exchanged via markdown-with-YAML files in a shared output directory.

When to Use

Rust application/library security review: safe/unsafe boundary auditing, memory safety in unsafe blocks, concurrency hazards, panic-induced DoS on servers, FFI safety, async-runtime mistakes.

When NOT to Use

  • Pure-C / pure-C++ codebases — use c-review instead.
  • Smart contracts (Solana programs / NEAR contracts / Ink!) — use solana-vulnerability-scanner or the contract-specific skill.
  • Kernel-mode Rust drivers without userspace allocator — coverage is incomplete; flag as advisory only.
  • Secrets/key memory hygiene (zeroization, Zeroize/ZeroizeOnDrop/secrecy usage, lingering stack/heap copies) — use the zeroize-audit skill; rust-review does not cover memory zeroization.

Subagents

| 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 |

Tools come from each agent's frontmatter at spawn time. The orchestrator's Task*/Agent/Bash/etc. come from this skill's allowed-tools. Search-tool / Bash interaction: in current Claude Code, an agent granted Bash is not also granted the dedicated Glob or Grep tools (the calls return No such tool available; the harness expects find/grep/rg via Bash instead). So only the dedup-judge — the one agent that holds no Bash — uses Glob; the worker, fp-judge, and the orchestrator resolve and search paths with Read / Bash find / rg / grep / test -f instead. Because the cluster/finder prompt seeds are written in ripgrep regex syntax (\s, \d, \b), Bash-holding agents must run them with rg. If rg is not installed its call fails loudly (command not found) — fall back to grep -E with POSIX classes (\s→[[:space:]], \d→[[:digit:]], drop \b), never a raw-\s grep whose silent empty becomes a bad cleared. Do not reintroduce Glob/Grep into a Bash-holding agent's protocol.


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

Output directory contains: context.md, plan.json, worker-prompts/, findings/, findings-index.d/ (per-worker shards), findings-index.txt, coverage/ (per-worker coverage-gate files), run-summary.md, dedup-summary.md, fp-summary.md, REPORT.md, REPORT.sarif.

Path convention: every later phase shells out to ${RUST_REVIEW_PLUGIN_ROOT}/scripts/*.py, so resolve that variable first to the plugin directory that contains prompts/clusters/unsafe-boundary.md (and scripts/build_run_plan.py). Try in order, first hit wins:

  1. Native Claude Code — ${CLAUDE_PLUGIN_ROOT}, accepted if Bash: ls "${CLAUDE_PLUGIN_ROOT}/prompts/clusters/unsafe-boundary.md" resolves.
  2. Codex — ${CODEX_PLUGIN_ROOT} (set it the same way if that var is present and resolves the marker).
  3. Fallback search — covers Codex installs under ~/.codex, Claude installs under ~/.claude, and a local checkout / repo run: Bash: find ~/.claude ~/.codex . -path '*/plugins/rust-review/prompts/clusters/unsafe-boundary.md' -print -quit 2>/dev/null. Take the match and strip the trailing /prompts/clusters/unsafe-boundary.md to get the root (the home dirs are searched before . so an installed copy wins over any vendored copy in the audited repo).

Set RUST_REVIEW_PLUGIN_ROOT to the resolved root. If all three fail, abort with a message naming the roots searched — do not enter Phase 4 with an empty variable (every uv run --no-project "${RUST_REVIEW_PLUGIN_ROOT}/scripts/..." call would fail with a confusing path error).

Scope convention: keep two scopes separate throughout the run:

  • finding_scope_root — the user-requested audit subtree. Workers may only file findings whose vulnerable location is inside this subtree.
  • context_roots — read-only repo roots/files workers and judges may inspect to verify reachability, callers, wrappers, build flags, mitigations, and threat-model details. Default to . unless the user explicitly forbids broader context. Reading context outside finding_scope_root is allowed; filing findings there is not.

Rationalizations to Reject

  • "unsafe is rare, so hand-skip the memory-safety cluster." Don't edit the cluster list — set has_unsafe accurately in Phase 1 and let build_run_plan.py decide. Every memory-safety bug class (UAF, double-free, uninitialized reads, Vec::set_len, union UB) requires unsafe, so the planner runs the whole memory-safety cluster when has_unsafe=true and correctly omits it when false — there is no "run it anyway." The unsafe-boundary cluster is different: it has no requires and always runs (consolidated; its safety-doc and repr(C) hygiene apply to FFI declarations even without visible unsafe { } blocks).
  • "The compiler caught it." The borrow checker proves absence of safe-code data races; it proves nothing about unsafe blocks, panic reachability, ABBA deadlocks, atomic-load/store sequencing, or FFI ABI mismatch.
  • "unwrap() is fine if it's // SAFETY: documented infallible." // SAFETY: documents unsafe operations, not infallibility claims. An unwrap() on documented-infallible input is still risky if the documentation is wrong — file as low severity and let the FP judge decide.
  • "has_unsafe=false so skip the run." Pure safe-Rust crates still have panic-DoS, atomic races, drop-panics, and trait-implementation hazards. Run the always-on clusters.
  • "Background spawns parallelize the workers." They do not — Agent calls in a single assistant message already run concurrently. run_in_background=true defeats the Phase 6a primer cache, so every worker pays full cache-creation (cache_read_input_tokens=0) and the ~15 K-token primer is wasted M times. Default: omit run_in_background from worker spawns.
  • "I'll re-derive the cluster list / paths / pass prefixes inline instead of running build_run_plan.py." The script is the only authority for selection and rendering. Paraphrasing it drops fields that the worker self-check requires, producing worker-N abort: spawn prompt malformed. Always run the script and Read plan.json.
  • "The run partially succeeded — I'll just write REPORT.md from what completed." Hiding partial runs behind a successful report is a correctness bug. If any Phase-5 cluster task is not completed, surface it prominently in run-summary.md and the final response.
  • "Zero findings — skip Phase 8." Always run both judges and Phase 8b: dedup-judge writes a minimal no-op dedup-summary.md on an empty index, fp-judge writes empty REPORT.md/REPORT.sarif, and Phase 8b's SARIF generator emits results: [] for the empty case. SARIF consumers depend on a stable artifact set.
  • "Bash: ls README* is fine for the preflight." Under zsh, an unmatched glob aborts the whole compound command before 2>/dev/null runs. Use find (never fails on no-match) — and not Glob, which is unavailable to an agent that also holds Bash.

Orchestration Workflow

Run these phases in the main conversation.

Phase 0: Parameter Collection

Entry: skill invoked. Exit: threat_model, worker_model, severity_filter resolved; scope_subpath resolved or set to "."; finding_scope_root=scope_subpath; context_roots resolved.

The skill is invoked directly (no command wrapper). Parse any free-text arguments the user passed on the /rust-review:rust-review line (e.g. flamenco only, high severity only, use haiku) and pre-fill the answers they imply — then ask for any missing required parameters with one AskUserQuestion call. Never silently default the required parameters.

Required parameters:

| Parameter | Values | How to infer from args | |---|---|---| | threat_model | REMOTE / LOCAL_UNPRIVILEGED / BOTH | Words like "remote", "network", "attacker" → REMOTE; "local", "unprivileged" → LOCAL_UNPRIVILEGED; otherwise ask. | | worker_model | haiku / sonnet / opus | Explicit model name in args. Otherwise ask (no silent default). | | severity_filter | all / medium / high | "all", "every", "noisy" → all; "medium and above" → medium; "high only", "criticals only" → high. Otherwise ask — no silent default. | | scope_subpath | repo-relative directory (optional) | Phrases like "X only", "just audit X/", "review subdirectory X" → src/X/ or the matching subdir. Apply fuzzy matching against top-level subdirectories of the repo. If absent, set "."; if ambiguous, ask. |

Call AskUserQuestion exactly once with only unresolved required parameters (threat_model, worker_model, severity_filter) plus scope_subpath only when the user explicitly requested a narrowed scope but it is ambiguous. If the required parameters were all pre-filled and scope is absent or resolved, skip the question.

After resolving scope_subpath, set finding_scope_root="${scope_subpath:-.}". Set context_roots="." by default so workers can verify callers/build settings outside a narrowed subtree without filing out-of-scope findings. If the user explicitly asks to forbid broader context, set context_roots="${finding_scope_root}" and note that reachability confidence may be lower.

Phase 1: Prerequisites

Entry: Phase 0 complete. Exit: has_unsafe, has_ffi, has_concurrency, has_async, has_packed_repr, has_fs_io flags determined. Abort with a clear message if no *.rs files exist under ${finding_scope_root}.

First confirm uv is present (command -v uv) — every helper script from Phase 4 onward runs through it. If missing, abort and tell the user to install it (brew install uv or the official installer); nothing downstream can run without it.

Probe within ${finding_scope_root:-.} with the Bash commands below (non-empty output ⇒ flag true). The dedicated Grep/Glob tools are unavailable to this orchestrator because it holds Bash — use grep/rg/find via Bash. (The probe regexes use \s/\b; if your grep lacks GNU \s support, run them with rg -uu — which honors \s and still searches ignored files — or, if rg is not installed either, replace \s→[[:space:]] and drop \b. Widening is safe here: a false-positive capability flag only adds a harmless extra worker, whereas a missed match would skip a whole pass.)

# Rust source presence (precondition)
find "${finding_scope_root:-.}" -name '*.rs' -print -quit

# has_unsafe
grep -rlE '\bunsafe\s+(extern|fn|impl|trait)\b|\bunsafe\s*\{' --include='*.rs' "${finding_scope_root:-.}" | head -

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars7.2k
CategorySecurity
Updated4d ago
Forks615

Languages

Python

Trust signals

100/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

No cautions