google/fuzzing-rust-expert
Use this skill to fuzz open source Rust software projects.
npx skills add https://github.com/google/oss-fuzz --skill fuzzing-rust-expert
This skill provides the agent with the knowledge and tools to write, build, and
validate fuzz targets for Rust projects integrated into OSS-Fuzz. Rust fuzzing
uses cargo-fuzz with the libfuzzer_sys crate, which drives libFuzzer.
Rust projects must use the Rust base builder image:
FROM gcr.io/oss-fuzz-base/base-builder-rust
Set language: rust in project.yaml.
Rust fuzz targets live in fuzz/fuzz_targets/<name>.rs within the crate being
fuzzed. The minimal harness using raw bytes:
#![no_main]
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: &[u8]| {
// Call into the target. The fuzzer will mutate `data` on every iteration.
let _ = my_crate::parse(data);
});
For structured fuzzing using the arbitrary crate (preferred when the target
expects typed input):
#![no_main]
use libfuzzer_sys::fuzz_target;
use arbitrary::Arbitrary;
#[derive(Debug, Arbitrary)]
struct MyInput {
header: u8,
payload: Vec<u8>,
flags: u32,
}
fuzz_target!(|input: MyInput| {
let _ = my_crate::process(input.header, &input.payload, input.flags);
});
The Cargo.toml for the fuzz directory must declare dependencies:
# fuzz/Cargo.toml
[package]
name = "my-crate-fuzz"
version = "0.0.0"
edition = "2021"
publish = false
[dependencies]
libfuzzer-sys = "0.4"
arbitrary = { version = "1", features = ["derive"] } # only if using structured fuzzing
[dependencies.my-crate]
path = ".."
[[bin]]
name = "fuzz_target_name"
path = "fuzz_targets/fuzz_target_name.rs"
test = false
doc = false
build.sh uses cargo fuzz build and then copies binaries to $OUT:
# build.sh
cd $SRC/<crate-dir>
cargo fuzz build -O # -O enables release optimisations; important for performance
FUZZ_TARGET_OUTPUT_DIR=$SRC/<crate-dir>/target/x86_64-unknown-linux-gnu/release
for f in fuzz/fuzz_targets/*.rs; do
name=$(basename "${f%.*}")
cp "$FUZZ_TARGET_OUTPUT_DIR/$name" "$OUT/"
done
If the project requires a nightly toolchain, set it in the Dockerfile:
ENV RUSTUP_TOOLCHAIN=nightly
Or pin to a specific nightly for reproducibility:
ENV RUSTUP_TOOLCHAIN=nightly-2025-07-03
fuzz/corpus/<target_name>/ within the repo; they areautomatically picked up by cargo-fuzz and can be zipped for OSS-Fuzz.
$OUT/<target_name>_seed_corpus.zip.$OUT/<target_name>.dict.beats hand-picking a few files — random mutation rarely passes the parser's
early checks (note: cargo-fuzz's arbitrary is the better route when the
target takes typed data rather than a byte format). See the [structured seed
generation reference](../oss-fuzz-engineer/references/structured_seed_generation.md).
unsafe blocks, and any API that processes untrusted bytes.
arbitrary) when the target expects typed datarather than raw bytes — this dramatically improves coverage.
Result and Option should be let-bound andignored (let _ = ...). Only actual panics are findings.
.unwrap() or .expect()on fallible operations driven by fuzz input — these create false positives.
rand, no system time, no thread spawninginside the fuzz callback.
callback; do those outside the fuzz_target! macro if needed with
LazyLock / OnceLock.
unsafe code: if the crate has unsafe blocks, writeharnesses that exercise those paths — this is where memory bugs can still
occur in Rust.
-O): fuzzing in debug mode is much slower.Rust's ownership model prevents most memory-corruption bugs, but fuzzing still
finds:
unwrap/expect on None/Err, index out of bounds,arithmetic overflow in debug mode, explicit panic! calls.
unsafe bugs: use-after-free, out-of-bounds reads/writes, undefinedbehaviour in unsafe blocks — these are real memory bugs.
python3 infra/helper.py build_fuzzers <project>
python3 infra/helper.py check_build <project>
python3 infra/helper.py run_fuzzer <project> <fuzzer_name> -- -max_total_time=30
panic! on every input — check for.unwrap() calls on fuzz-driven paths and replace with if let or ?.
cargo build and cargo test inside the crate before adding the fuzzharness to catch pre-existing compilation errors.
RUN git clone to COPY to avoid network round-trips.
no_std, use libfuzzer-sys's no_std feature and ensurethe harness does not rely on std.
Take google/fuzzing-rust-expert from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.