Install any skill in seconds. Free to start, no credit card required.
Get Started Free →cargo-fuzz is the de facto fuzzing tool for Rust projects using Cargo. Use for fuzzing Rust code with libFuzzer backend.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 194% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 148% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 86% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 427% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 163% | 0% |
cargo-fuzz is the de facto choice for fuzzing Rust projects when using Cargo. It uses libFuzzer as the backend and provides a convenient Cargo subcommand that automatically enables relevant compilation flags for your Rust project, including support for sanitizers like AddressSanitizer.
cargo-fuzz is currently the primary and most mature fuzzing solution for Rust projects using Cargo.
| Fuzzer | Best For | Complexity | |--------|----------|------------| | cargo-fuzz | Cargo-based Rust projects, quick setup | Low | | AFL++ | Multi-core fuzzing, non-Cargo projects | Medium | | LibAFL | Custom fuzzers, research, advanced use cases | High |
Choose cargo-fuzz when:
rust#![no_main] use libfuzzer_sys::fuzz_target; fn harness(data: &[u8]) { your_project::check_buf(data); } fuzz_target!(|data: &[u8]| { harness(data); });
Initialize and run:
bashcargo fuzz init # Edit fuzz/fuzz_targets/fuzz_target_1.rs with your harness cargo +nightly fuzz run fuzz_target_1
cargo-fuzz requires the nightly Rust toolchain because it uses features only available in nightly.
bash# Install nightly toolchain rustup install nightly # Install cargo-fuzz cargo install cargo-fuzz
bashcargo +nightly --version cargo fuzz --version
cargo-fuzz works best when your code is structured as a library crate. If you have a binary project, split your main.rs into:
textsrc/main.rs # Entry point (main function) src/lib.rs # Code to fuzz (public functions) Cargo.toml
Initialize fuzzing:
bashcargo fuzz init
This creates:
textfuzz/ ├── Cargo.toml └── fuzz_targets/ └── fuzz_target_1.rs
rust#![no_main] use libfuzzer_sys::fuzz_target; fn harness(data: &[u8]) { // 1. Validate input size if needed if data.is_empty() { return; } // 2. Call target function with fuzz data your_project::target_function(data); } fuzz_target!(|data: &[u8]| { harness(data); });
| Do | Don't | |----|-------| | Structure code as library crate | Keep everything in main.rs | | Use fuzz_target! macro | Write custom main function | | Handle Result::Err gracefully | Panic on expected errors | | Keep harness deterministic | Use random number generators |
> See Also: For detailed harness writing techniques and structure-aware fuzzing with the > arbitrary crate, see the fuzz-harness-writing technique skill.
cargo-fuzz integrates with the arbitrary crate for structure-aware fuzzing:
rust// In your library crate use arbitrary::Arbitrary; #[derive(Debug, Arbitrary)] pub struct Name { data: String }
rust// In your fuzz target #![no_main] use libfuzzer_sys::fuzz_target; fuzz_target!(|data: your_project::Name| { data.check_buf(); });
Add to your library's Cargo.toml:
toml[dependencies] arbitrary = { version = "1", features = ["derive"] }
bashcargo +nightly fuzz run fuzz_target_1
If your project doesn't use unsafe Rust, disable sanitizers for 2x performance boost:
bashcargo +nightly fuzz run --sanitizer none fuzz_target_1
Check if your project uses unsafe code:
bashcargo install cargo-geiger cargo geiger
bash# Run a specific test case (e.g., a crash) cargo +nightly fuzz run fuzz_target_1 fuzz/artifacts/fuzz_target_1/crash-<hash> # Run all corpus entries without fuzzing cargo +nightly fuzz run fuzz_target_1 fuzz/corpus/fuzz_target_1 -- -runs=0
bashcargo +nightly fuzz run fuzz_target_1 -- -dict=./dict.dict
| Output | Meaning | |--------|---------| | NEW | New coverage-increasing input discovered | | pulse | Periodic status update | | INITED | Fuzzer initialized successfully | | Crash with stack trace | Bug found, saved to fuzz/artifacts/ |
Corpus location: fuzz/corpus/fuzz_target_1/ Crashes location: fuzz/artifacts/fuzz_target_1/
ASan is enabled by default and detects memory errors:
bashcargo +nightly fuzz run fuzz_target_1
For pure safe Rust (no unsafe blocks in your code or dependencies):
bashcargo +nightly fuzz run --sanitizer none fuzz_target_1
Performance impact: ASan adds ~2x overhead. Disable for safe Rust to improve fuzzing speed.
bashcargo install cargo-geiger cargo geiger
> See Also: For detailed sanitizer configuration, flags, and troubleshooting, > see the address-sanitizer technique skill.
cargo-fuzz integrates with Rust's coverage tools to analyze fuzzing effectiveness.
bashrustup toolchain install nightly --component llvm-tools-preview cargo install cargo-binutils cargo install rustfilt
bash# Generate coverage data from corpus cargo +nightly fuzz coverage fuzz_target_1
Create coverage generation script:
bashcat <<'EOF' > ./generate_html #!/bin/sh if [ $# -lt 1 ]; then echo "Error: Name of fuzz target is required." echo "Usage: $0 fuzz_target [sources...]" exit 1 fi FUZZ_TARGET="$1" shift SRC_FILTER="$@" TARGET=$(rustc -vV | sed -n 's|host: ||p') cargo +nightly cov -- show -Xdemangler=rustfilt \ "target/$TARGET/coverage/$TARGET/release/$FUZZ_TARGET" \ -instr-profile="fuzz/coverage/$FUZZ_TARGET/coverage.profdata" \ -show-line-counts-or-regions -show-instantiations \ -format=html -o fuzz_html/ $SRC_FILTER EOF chmod +x ./generate_html
Generate HTML report:
bash./generate_html fuzz_target_1 src/lib.rs
HTML report saved to: fuzz_html/
> See Also: For detailed coverage analysis techniques and systematic coverage improvement, > see the coverage-analysis technique skill.
| Tip | Why It Helps | |-----|--------------| | Start with a seed corpus | Dramatically speeds up initial coverage discovery | | Use --sanitizer none for safe Rust | 2x performance improvement | | Check coverage regularly | Identifies gaps in harness or seed corpus | | Use dictionaries for parsers | Helps overcome magic value checks | | Structure code as library | Required for cargo-fuzz integration |
Pass options to libFuzzer after --:
bash# See all options cargo +nightly fuzz run fuzz_target_1 -- -help=1 # Set timeout per run cargo +nightly fuzz run fuzz_target_1 -- -timeout=10 # Use dictionary cargo +nightly fuzz run fuzz_target_1 -- -dict=dict.dict # Limit maximum input size cargo +nightly fuzz run fuzz_target_1 -- -max_len=1024
bash# Experimental forking support (not recommended) cargo +nightly fuzz run --jobs 1 fuzz_target_1
Note: The multi-core fuzzing feature is experimental and not recommended. For parallel fuzzing, consider running multiple instances manually or using AFL++.
The ogg crate parses Ogg media container files. Parsers are excellent fuzzing targets because they handle untrusted data.
bash# Clone and initialize git clone https://github.com/RustAudio/ogg.git cd ogg/ cargo fuzz init
Harness at fuzz/fuzz_targets/fuzz_target_1.rs:
rust#![no_main] use ogg::{PacketReader, PacketWriter}; use ogg::writing::PacketWriteEndInfo; use std::io::Cursor; use libfuzzer_sys::fuzz_target; fn harness(data: &[u8]) { let mut pck_rdr = PacketReader::new(Cursor::new(data.to_vec())); pck_rdr.delete_unread_packets(); let output = Vec::new(); let mut pck_wtr = PacketWriter::new(Cursor::new(output)); if let Ok(_) = pck_rdr.read_packet() { if let Ok(r) = pck_rdr.read_packet() { match r { Some(pck) => { let inf = if pck.last_in_stream() { PacketWriteEndInfo::EndStream } else if pck.last_in_page() { PacketWriteEndInfo::EndPage } else { PacketWriteEndInfo::NormalPacket }; let stream_serial = pck.stream_serial(); let absgp_page = pck.absgp_page(); let _ = pck_wtr.write_packet( pck.data, stream_serial, inf, absgp_page ); } None => return, } } } } fuzz_target!(|data: &[u8]| { harness(data); });
Seed the corpus:
bashmkdir fuzz/corpus/fuzz_target_1/ curl -o fuzz/corpus/fuzz_target_1/320x240.ogg \ https://commons.wikimedia.org/wiki/File:320x240.ogg
Run:
bashcargo +nightly fuzz run fuzz_target_1
Analyze coverage:
bashcargo +nightly fuzz coverage fuzz_target_1 ./generate_html fuzz_target_1 src/lib.rs
| Problem | Cause | Solution | |---------|-------|----------| | "requires nightly" error | Using stable toolchain | Use cargo +nightly fuzz | | Slow fuzzing performance | ASan enabled for safe Rust | Add --sanitizer none flag | | "cannot find binary" | No library crate | Move code from main.rs to lib.rs | | Sanitizer compilation issues | Wrong nightly version | Try different nightly: rustup install nightly-2024-01-01 | | Low coverage | Missing seed corpus | Add sample inputs to fuzz/corpus/fuzz_target_1/ | | Magic value not found | No dictionary | Create dictionary file with magic values |
| Skill | Use Case | |-------|----------| | fuzz-harness-writing | Structure-aware fuzzing with arbitrary crate | | address-sanitizer | Understanding ASan output and configuration | | coverage-analysis | Measuring and improving fuzzing effectiveness | | fuzzing-corpus | Building and managing seed corpora | | fuzzing-dictionaries | Creating dictionaries for format-aware fuzzing |
| Skill | When to Consider | |-------|------------------| | libfuzzer | Fuzzing C/C++ code with similar workflow | | aflpp | Multi-core fuzzing or non-Cargo Rust projects | | libafl | Advanced fuzzing research or custom fuzzer development |
Rust Fuzz Book - cargo-fuzz Official documentation for cargo-fuzz covering installation, usage, and advanced features.
arbitrary crate documentation Guide to structure-aware fuzzing with automatic derivation for Rust types.
cargo-fuzz GitHub Repository Source code, issue tracker, and examples for cargo-fuzz.
Other measured skills in the registry, with their headline benchmark lift.