Overview
Fuzzing is an automated testing technique that finds bugs by providing random or mutated inputs to code. Bitcoin Core supports multiple fuzzing engines:- libFuzzer - LLVM’s coverage-guided fuzzer (recommended)
- AFL++ - Advanced fuzzing with instrumentation
- Honggfuzz - Security-oriented fuzzer
- Memory safety issues
- Assertion failures
- Crashes and undefined behavior
- Edge cases not covered by unit tests
- Denial-of-service vulnerabilities
Benchmarks are ill-suited for denial-of-service testing as they use restricted input sets. Fuzz tests explore the full input space and are better suited for this purpose.
Quick Start with libFuzzer
Build and Run
Fuzz Runner Script
Execute all fuzz targets using the runner:Understanding Fuzz Output
libFuzzer Output
The fuzzer outputsNEW when it creates an input that covers new code areas:
- cov: Code coverage (edges covered)
- ft: Feature count (more detailed coverage)
- corp: Corpus size (number of inputs / total bytes)
- exec/s: Executions per second
- rss: Resident set size (memory usage)
Using Corpus Directories
Specify a corpus directory to save coverage-increasing inputs:Fuzzing Harnesses
Available harnesses are insrc/test/fuzz/.
Example: process_message - Fuzzes the ProcessMessage() function in net_processing.
List all available targets:
Passing bitcoind Arguments
Fuzz tests can accept bitcoind arguments (some may ignore them):-- to distinguish fuzzer args from bitcoind args.
Fuzzing Corpora
The official seed corpora collection is atbitcoin-core/qa-assets.
Using qa-assets
Sanitizers
Address and Undefined Behavior Sanitizers
Default libFuzzer preset includes sanitizers:Memory Sanitizer (MSan)
MSan requires all linked code to be instrumented:- Compile
clangfrom source - Use it to compile an instrumented libc++
- Build Bitcoin Core dependencies from source with instrumentation
- Build the fuzz binary
Running Without Sanitizers
For increased throughput (finding new coverage faster):Fuzzing with sanitizers is good for finding bugs. Fuzzing without sanitizers is good for finding new coverage. A good strategy: run long sessions without sanitizers to find coverage, then merge inputs and test with sanitizers to find bugs.
Reproducing CI Crashes
Steps to Reproduce
-
Update qa-assets:
-
Locate crash case from CI output:
- Compile with sanitizers if needed
-
Run fuzzer with the crash input:
Using Base64 Encoded Input
If the file isn’t in qa-assets, use the base64 from CI logs:Contributing Coverage
If you find coverage-increasing inputs, submit them tobitcoin-core/qa-assets.
Building Fuzz Tests
Three ways to build fuzz tests:1. BUILD_FOR_FUZZING=ON (Standard)
- Forces on fuzz determinism
- Skips proof-of-work checks
- Disables random number seeding
- Disables clock time
Assume()checks abort on failure- Only fuzz binary can be built (other binaries disabled)
2. BUILD_FUZZ_BINARY=ON with Debug (Optional Determinism)
Assume()checks abort on failure- Determinism enabled by default
- Can disable determinism with
FUZZ_NONDETERMINISMenvironment variable - Allows non-fuzz binaries to coexist
3. BUILD_FUZZ_BINARY=ON with Release (Compile-only)
- Fuzz binary builds but refuses to run
- Determinism forced off
Assume()checks don’t abort
Coverage Reports
Generate fuzz coverage reports with Clang:build/coverage_report/index.html.
See also: Developer Notes - Compiling for Fuzz Coverage
Alternative Fuzzing Engines
AFL++ (American Fuzzy Lop)
Honggfuzz
OSS-Fuzz Integration
Bitcoin Core participates in Google’s OSS-Fuzz program. Resources:Bitcoin Core follows its own security disclosure policy, which may differ from Google’s standard 90-day disclosure window.
macOS Notes
Fuzzing support on macOS is not officially maintained. Recommendation: Fuzz on Linux for best results. Use Docker or a virtual machine on macOS. Reproducing crashes on macOS: Build the fuzz binary without a specific fuzzing engine:External Resources
- Google Fuzzing Overview
- Bitcoin Core Fuzzing Paper (2021)
- Writing Fuzzer-Friendly Code by John Regehr
- libFuzzer Documentation
- AFL++ Documentation
- Honggfuzz Documentation
Best Practices
Fuzzing Strategy
- Start with corpus: Use qa-assets seed corpus for better initial coverage
- Run long sessions: Fuzzing may need days and millions of executions to reach deep targets
- Alternate modes: Periodically switch between sanitizer and non-sanitizer builds
- Merge corpora: Regularly merge new inputs back to qa-assets
- Focus on targets: Prioritize fuzzing of security-critical components
Writing Fuzz Harnesses
- Keep harnesses simple and focused
- Minimize state between iterations
- Test one component or interface per harness
- Add assertions to catch unexpected states
- Avoid sources of non-determinism (random numbers, timestamps)
- Document what the harness tests
Performance Tips
- Use
-max_lento limit input size for faster iteration - Run multiple instances in parallel (
-fork=N) - Use corpus minimization (
-merge=1) - Profile to ensure fuzzer spends time in target code, not setup