This guide walks you through fuzzing a target with source code available. For binary-only targets, see the Binary-only fuzzing documentation.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/AFLplusplus/AFLplusplus/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Fuzzing with AFL++ involves three steps:- Instrument the target - Compile with AFL++ compilers to add instrumentation
- Prepare seeds - Collect and optimize initial input corpus
- Run afl-fuzz - Execute the fuzzer to find bugs
Step 1: Instrument your target
Select the AFL++ compiler
Choose the best compiler for your setup:LTO mode (best)
LLVM mode (good)
GCC_PLUGIN mode (fallback)
It is highly recommended to have the newest LLVM version possible installed. Anything below LLVM 9 is not recommended.
Compile the target
Forconfigure-based build systems:
Advanced: Enable CMPLOG (recommended)
CMPLOG helps solve complex comparisons and magic bytes:-c flag during fuzzing.
Advanced: Enable LAF-INTEL (alternative)
LAF-INTEL splits complex comparisons:CMPLOG is usually more effective than LAF-INTEL. Use LAF-INTEL when targets heavily transform input before comparison.
Step 2: Prepare seed inputs
Collect initial inputs
Gather valid input files for your target:- Example files from the target’s test suite
- Sample files from bug reports
- Files downloaded from the internet
- Files generated by running the target normally
Create seeds directory
Optional: Minimize the corpus
Remove redundant inputs that don’t provide new coverage:The
@@ symbol is replaced by AFL++ with the path to the test input file.Optional: Minimize individual files
Shorter inputs fuzz faster:Step 3: Run afl-fuzz
System configuration
Before fuzzing, configure your system for optimal performance:Basic fuzzing
Start fuzzing with the minimal configuration:-i seeds: Input directory with seed files-o output: Output directory (created automatically)--: Separates afl-fuzz options from target command./target: Your instrumented binary@@: Placeholder for input filename (omit if target reads from stdin)
With CMPLOG
If you compiled a CMPLOG binary:With a dictionary
Dictionaries help with verbose formats (SQL, HTTP, etc.):dictionaries/ directory.
Setting memory limits
Limit memory usage to prevent OOM and find malloc failures:Full example with recommended options
Understanding the UI
When afl-fuzz runs, you’ll see a status screen:- last new find: Time since last new path was discovered
- total crashes: Number of unique crashes found
- exec speed: Executions per second (higher is better)
- map coverage: Percentage of instrumentation points hit
Analyzing results
Finding crashes
Crashes are saved in the output directory:id:NNNNNN,sig:NN,src:NNNNNN,...
Reproducing crashes
Test a crash manually:Debugging crashes
Use GDB to investigate:Finding hangs
Inputs that cause timeouts are saved in:Stopping and resuming
Stop fuzzing
PressCtrl+C or send SIGINT to afl-fuzz.
Resume fuzzing
Reuse the same command but replace-i seeds with -i -:
AFL_AUTORESUME=1 to auto-resume:
Multi-core fuzzing
Start the main fuzzer
Start secondary fuzzers
In separate terminals (or screen/tmux sessions):- One with CMPLOG:
-c target-cmplog -l 2AT - One with sanitizers (ASAN/UBSAN)
- Different power schedules:
-p fast,-p explore,-p exploit - Some with MOpt:
-L 0 - Some with old queue cycling:
-Z
Check fuzzing status
Monitor all instances:Next steps
This quickstart covers the basics. For professional fuzzing campaigns, read the complete fuzzing in depth guide.
- Use persistent mode for 2-20x speed improvement
- Use libfuzzer harnesses with
LLVMFuzzerTestOneInput() - Implement custom mutators for domain-specific formats
- Enable sanitizers to find non-crashing bugs
- Read about best practices for network services and GUI programs
- Fuzzing in depth - Complete fuzzing guide
- Persistent mode - Much faster fuzzing
- Best practices - Advanced techniques
- FAQ - Common questions

