Fuzzlands: Map of the Wider Fuzzing Landscape
For my fuzzing workshop at Protocol Berg 2025, I recently donned my cartographer’s boots and perhaps a pair of archival gloves! to document the past and present of industrial-strength fuzzing tools If you are looking for a textbook on fuzzing techniques instead, I recommend the excellent online Fuzzing Book by Andreas Zeller et al..
Although fuzzing — the art of testing software by feeding it random inputs — is a relatively recent development (having reached industrial strength only in the last fifteen years or so), the sheer number of available tools already makes navigating this landscape quite challenging. This article is a summary of my findingsThis is a work in progress. If you have suggestions for additions or changes, please get in touch. — a map of the fuzzing landscape circa 2025 CE — intended to guide those venturing into the fuzzing jungle.
❦ ❦ ❦
Fuzzer Types: Broad Categories
Fuzzing is a broad field, and there are many different tools and techniques available. Before we jump into the list of fuzzers below, let’s take a moment to understand the different types of fuzzers and how they differ. We can categorize fuzzers along two main dimensions: the level of insight they have into the target program, and how they generate inputs.
Insight Levels: 50 Shades of Grey
Fuzzing tools can be categorized based on the level of insight they possess (or utilize) regarding the target program the fuzz target, or system under test.
This spectrum of insight extends from complete unawareness of the program’s inner workings (black-box fuzzing also known as protocol fuzzing) to comprehensive utilization of the target’s source code (white-box fuzzing) — the latter enabling static program analysis such as symbolic execution the combination of concrete and symbolic exploration is aptly named concolic execution. Grey-box fuzzing occupies the middle ground, where the fuzzer leverages partial knowledge of the program’s structure — frequently utilizing coverage information Coverage information is often obtained via source code or binary instrumentation for compiled languages, via VM counters for interpreted languages, and sometimes even via hardware counters..
Input Generation: Gen XY-Mutation
A second way to categorize fuzzers is by how they generate inputs. Mutation-based fuzzers are inspired by genetic algorithms and apply selection and mutation such as flipping bits, inserting bytes, or splicing portions of previously selected inputs operators to create new inputs (this necessitates having some evolutionary insight into which inputs are worth mutating — like coverage information, see above). Generation-based fuzzers, on the other hand, generate inputs from scratch, often using a grammar or other formal specification of the input format.
❦ ❦ ❦
Map of the Fuzzlands, As Known to Mankind
Heed my warning: stay on the path or here be dragons! Just kidding — jump around and explore as you like — this is not NetHack, you can always back-track.
We start our journey through the fuzzing landscape in the Black-Box Continent, where the oldest fuzzers where born, and where rugged exploration algorithms plow through a tarrain obscured by thick fog. From there, we venture into the Grey-Box Midlands, where genious engineers have equipped their versatile fuzzers with advanced guidance systems. Finally, we reach the White-Box Peaks, where sophisticated but fragile tools with magic-like capabilities reside.
Black-Box Continent: Fog of War
The Black-Box Continent is an ancient, vast, and foggy land, where the fuzzers have no insight into the target program’s inner workings. It is divided into the Protocol-Fuzzing Madlands, where generation-based fuzzers interact with unobservable systems at large, and the Property-based Testing Plateau, where testing frameworks generate inputs and assert properties at the level of unit or integration tests.
𐫱
Protocol-Fuzzing Madlands: Ancient, Powerful, Blind
Peach 2004
Peach is one of the earliest fuzzing platforms (and in contrast to most other fuzzing tools here a commercial one!). It has been used extensively in the security industry to test network protocols and file formats. Peach supports both mutation-based which Peach calls “dumb fuzzing” and generation-based less condescending: “file fuzzing” input generation — the latter generating inputs according to XML descriptions of the target format known as pit files. Original developer Peach Tech has been acquired by Gitlab in 2020, who have open-sourced its core engine as GitLab Protocol Fuzzer Community Edition.
Csmith 2011
Csmith, a fuzzer with a clear agenda, is a specialized fuzzer that generates random, valid C programs. Its purpose is to test C compilers for correctness and robustness, rather than to find bugs in general application or systems code. Csmith claims to output C programs free of undefined behavior which, if you’ve ever peeked into the C standard, is a tall order!. Exciting academic work like this deserves a link to the paper, deservedly published at PLDI.
Sulley 2007
Sulley named after the blue monster from Pixar’s Monsters, Inc. is an early open-source fuzzing framework aimed at (network) protocol fuzzing. It allows users to use code to define protocol states and input grammars, supports failure detection and can generate complex test cases for network services. Development has ceased, but Sulley lives on in...
boofuzz 2012
boofuzz named after Boo, the human child from Monsters, Inc. is a modern fork and continuation of Sulley, aiming to provide a more robust and actively maintained network protocol fuzzing framework. It retains Sulley’s core concepts — such as protocol definitions, input modeling, and automation — while introducing additional abstractions and improving stability and usability. Boo!
𐫱
Property-based Testing Plateau
We now enter the Property-based Testing Plateau — instead of the behemoths of old, this land is populated by small, nimble input generators and assertion frameworks. These tools are used in property-based testing (PBT) — unit- or integration-level tests of software, where instead of specifying concrete input-output pairs, PBT libraries generate inputs, and then assert that the exercised code exhibits certain properties. They are often used in conjunction with other testing frameworks or assertion libraries.
Quickcheck, Hypothesis, propcheck, forge fuzz, ... 2000s
Your cartographer insists that THESE TOOLS ARE NOT FUZZERS which doesn’t mean I don’t enjoy using them — for the right task! (at least not in the traditional sense). Nevertheless, confusion abounds — for example, the Foundry toolchain for Solidity calls its PBT framework “Fuzz Testing”.
Other examples of this breed include the original Quickcheck for Haskell, QuickChick for Coq, ScalaCheck for Scala, Hypothesis for Python, QuickCheck and proptest for Rust, and forge fuzz for Solidity.
❧
Grey-Box Midlands: Coverage-Guided Seekers
The Grey-Box Midlands are the rolling hills of the fuzzing landscape, where some of the most powerful fuzzers emerged, and some of the most popular fuzzers still reside. The fuzzers in the Midlands are coverage-guided, meaning they use coverage information from the target program to guide their input generation, to explore the target program’s code more effectively.
The Midlands range from the Byte[] Lowlands, where inputs are merely sequences of bytes, to the Structure-Aware Hillcountry, which borders on the generation-based lands of the Black-Box Continent, where fuzzers are aware of the structure of the target program’s input format and can generate inputs accordingly.
𐫱
Byte[] Lowlands: The Birthplace of Coverage-Guided Fuzzing
We start our journey in the Byte[] Lowlands, where the first coverage-guided fuzzers were born.These fuzzers generate inputs as sequences of bytes, without any knowledge of the structure of the target program’s input format.Intutively, we can see how this is useful for fuzzing something like an image viewer or Microsoft Word, where the input file format is (or used to be) just a binary blob. However, they receive coverage information (which code has been covered by an execution) from the target program, and use it to guide their input generation, often using mutation-based techniques.
AFL: The Grandfather of Coverage-Guided Fuzzers 2013
AFL (american fuzzy
lop) The
American Fuzzy Lop is
a rabbit breed recognized by the American Rabbit Breeders Association (ARBA).
is the homey (if a bit paranoid Besides the fuzzer, its author offers
the thoroughly-researched book
Practical Doomsday. $24.92 on
Amazon.) grampa of coverage-guided fuzzers, and has inspired a whole generation
of them. It obtains coverage information either via source code instrumentation
(using its own compiler wrappers, such as afl-gcc
), or via binary
instrumentation, using QEMU’s “user space emulation”. An out-of-process
fuzzer, AFL runs in a process separate from it’s target, and uses a fork server
to spawn new fuzz runs. Documentation and usage notes are plentily available in
sprinkles around the web, including the
offical docs and
the author’s previous blog.
AFLplusplus: The Next Generation 2019
Oh, did I mention that AFL is unmaintained? Luckily, the community has forked it and is actively working on it under the name AFLplusplus or AFL++?. This fork adds a plethora of new features, stability and usability improvements, alongside a more structured documentation.
libFuzzer: The LLVM Fuzzer 2015
libFuzzer is another coverage-guided fuzzer, part of the LLVM project (with major contributions from Google), and a tiny bit younger than AFL. Besides being an in-process fuzzer it runs in the same process as the target program, it uses LLVM’s own SanitizerCoverage to obtain coverage information. While its authors have moved on to develop FuzzTest (a fuzzer we know little about), libFuzzer is actively maintained and widely used, especially in the C/C++ and Rust ecosystems (more on Rust fuzzing below). As you would expect from an LLVM project, it is well-documented.
Honggfuzz: The Fuzzer from Zurich 2016
Another fuzzer from the Google stables, Honggfuzz is yet another coverage-guided fuzzer. Focused on throughput, it supports both multi-process and multi-threaded fuzzing.
𐫱
Interlude: Rusty Mountains and JVM Valleys
While generally aimed at binaries and implicitly at C/C++ programs, the coverage-guided fuzzers listed above can also be used to fuzz programs written in other languages.
libFuzzer in particular has generated a whole ecosystem of offspring: cargo-fuzz is a toolchain-wrapper for
libFuzzer, making Rust fuzzing as easy as typing cargo fuzz run
Well, not really. Good fuzzing is hard..
jazzer, by Code Intelligence Labs, is a port of libFuzzer to the JVM.
Even more libFuzzer descendants follow below!
Honggfuzz has a Rust port, too: honggfuzz-rs.
For even more Rust fuzz, the Rust Fuzzing Authority has you covered — though documentation is sparse beyond the eponymous Rust Fuzz Book.
𐫱
Structure-Aware Hillcountry
Still part of the Grey-Box Midlands of coverage-guided fuzzing, but nestling against the hills towards the Property-Based Testing Plateau of the Black-Box Continent, we find ourselves in the Structure-Aware Hillcountry. Often derived from the coverage-guided fuzzers above, these fuzzers attempt to support the structure of the target program’s input format which can result in more efficient fuzzing for complex input types, if your target does not like byte soup. As an example, imagine a struct that contains a string as well as the string’s checksum., rather than just spitting out random bytes.
Structure-aware Fuzzing with libFuzzer 2017
libFuzzer can venture into the Structure-Aware Hillcountry by deserializing its generated bytes to a compact binary encoding e.g., protobuf (Hi there again, Google!) combined with custom mutation functions that work directly on the structure of the target program’s input format. Details in the docs or this talk.
cargo fuzz + arbitrary 2019
Another
attempt
at structure-aware fuzzing with libFuzzer (if you remember, cargo-fuzz is a
Rust toolchain wrapper around libFuzzer). This one borrows the
arbitrary
crate
from property-based testing (see above) to generate Rust data structures.
Instead of relying on the system
PRNG to
produce values, it uses the byte[] input from libFuzzer as its source of
entropy.
This is quite the mix, indeed and supported in cargo fuzz: it is generation-based, so you can generate semantically correct data structures without having to worry about meaningful deserialization of a byte string, and it’s coverage-guided, which incentivizes the fuzzer to explore new code paths. On the other hand, as pointed out here, it also marries two unrelated concepts at an unnecessarily low-level interface: small mutations to the byte[] may send the fuzzer down a completely different path than intended, and the fuzzer has no way of knowing that. This is a great example of combining the strengths of two different fuzzing paradigms, but perhaps also an example of how not to do it.
Fuzzcheck: structure-aware and feedback-driven 2019
Unlike the other attempts we’ve seen to infuse coverage-guided fuzzing with structure-aware input generation, Fuzzcheck does not use an intermediary binary encoding, nor does it use generators. Instead, it directly mutates the typed values in-process.Your cartographer likes this idea! It sounds clean and efficient — unfortunately, I have not yet had the chance to try it out. Sign up for updates below if you want to hear about my experiences once I take Fuzzcheck for a spin.
Do not confuse with FuzzChick for Coq.
syzkaller: The Kernel Fuzzer 2015
syzkaller is a niche fuzzer, but conceptually one of the most interesting ones on this list: it targets the Linux kernel and like Fuzzcheck, it does a clean combination of coverage-guided and generation-based fuzzing.
Born out of an attempt to apply real coverage-guided fuzzing to the kernel (in addition to sanitizers instrumented into code driven by random inputs), it has evolved into a fully-fledged kernel fuzzer that uses a custom declarative language to describe syscall interfaces and generates sequences of system calls from them.See what happened here? We went from firing solo inputs driving single-shot executions to multi-statement programs driving an episodic, stateful system. Like libFuzzer, it uses LLVM’s SanitizerCoverage to obtain coverage information.
𐫱
LibAFL: Touche‑à‑Tout Future Modular Megacity 2021
Before we venture into the snow-covered White-Box Peaks, we decide to splurge and visit LibAFL, the sparkling megapolis of the future raised in the land’s heart. Bustling with busy construction work, this framework of tomorrow integrates fuzzers and ideas of old and new, both nimble and heavy, from all over the land. Hailed by many, understood by few, LibAFL is not an offspring or improvement of AFL though it’s name might lead you to think so, but a complete reimagination of how to do fuzzing: Instead of a fuzzer, this is a framework, with a focus on modularity and extensibility.
I, for one, prefer tunable tools over frameworks. Supervising a running fuzzing campaign can already feel like herding cats — assembling my own FrankenFuzzer from scratch at the same time is not exactly my idea of fun. Be warned, though: this is not a fuzzer you can just pick up and use without learning to wield this powerful tool while assembling your fuzzer building blocks like LEGO bricks, fellow warrior!
❧
White-Box Peaks: The Summit of Static Analysis
Finally, we reach the White-Box Peaks. Among the glistening peaks roam elvenlike tools held together by threads of mystical golden silk spun by the tender hands of CS PhD students or is it hair, torn out in desparation before the paper deadline? and researchers. These fuzzers are the most powerful — in theory. In practice, they might not be the most predictable ones (unless you’ve brought your spellbook with you).
KLEE: The Symbolic Executor 2008
KLEE is a symbolic execution tool developed at MIT and later Stanford. Built on the LLVM compiler infrastructure, performs pure symbolic execution on LLVM bitcode. This means it treats program inputs as symbolic variables, explores all feasible execution paths by generating and solving constraints. It aims to automatically generate high-coverage tests by exploring many possible execution paths using these symbolic inputs. Its strength lies in its effectiveness for small to medium-sized applications and in detecting low-level bugs like memory errors. KLEE has been used to find bugs in various software projects, including Linux Coreutils.
S2E: Selective Symbolic Execution 2009
Building on KLEE, S2E gives users more control over what parts of the code are analyzed symbolically. This selective approach allows deeper exploration of specific code regions while avoiding the path explosion problem in irrelevant areas.
SAGE: Scalable Automated Guided Execution 2008
Unlike KLEE’s pure symbolic approach, SAGE combines concrete execution with symbolic execution (concolic execution). Developed at Microsoft Research, SAGE is a whitebox fuzzer that executes the program with concrete inputs, while simultaneously collecting symbolic constraints along the executed path. When a new path needs to be explored, SAGE negates a path condition and uses a constraint solver to generate new concrete inputs that steer execution down that alternative pathKeep in mind that this approach has limits. Not even SAGE can invert that hash function inside your path condition.. This hybrid approach allows SAGE to effectively navigate complex programs and has been instrumental in finding numerous security bugs in large-scale commercial software, including Windows.
angr: The Binary Analysis Framework 2015
angr is a versatile, multi-architecture binary analysis framework written in Python. Unlike KLEE, which operates on LLVM bitcode, angr lifts binary executables from various architectures (x86, ARM, MIPS, etc.) into an intermediate representation called VEX. This allows it to perform a wide range of analyses, including symbolic execution, static analysis, and dynamic analysis. Its flexibility and programmatic interface make it a popular choice for security researchers and CTF participants for tasks like vulnerability discovery, exploit generation, and malware analysis.
Driller: Auto-Selective Hybrid Fuzzing 2016
Driller is another hybrid tool that combines the strengths of fuzzing with selective concolic execution. It aims to overcome the limitations of both techniques: fuzzing’s inability to penetrate deep, complex logic and symbolic execution’s “path explosion” problem. Driller starts with an inexpensive fuzzer (like AFL) to explore readily accessible code paths. When the fuzzer gets stuck at a complex branch condition, Driller employs concolic execution (similar to SAGE’s approach, but selectively applied) to generate precise inputs that satisfy those difficult conditions and guide the fuzzer further into the program.
❦ ❦ ❦
This concludes our journey through the fuzzing landscape. We have mapped the past and present of fuzzing tools, from the ancient ones of the Black-Box Continent, through the coverage-guided ones of the Grey-Box Midlands, to the sophisticated white-box fuzzers of the White-Box Peaks.
This is not a complete list — the most obvious omissions are fuzzers for Go (TODO) and for smart contracts (e.g., Echidna and Medusa for Solidity/EVM). I plan to add these in the future, and you can sign up below to be notified when I do.
Even so, I hope this map provides a good overview of the fuzzing landscape as it stands in 2025. It highlights the diversity of fuzzing tools and techniques available, and the different approaches they take to testing software. It also shows how fuzzing has evolved over the years, from a niche technique to a powerful (if complex) tool for finding bugs in software.
𐫱
Get in Touch
Ever tried fuzzing? Think anything is missing from this map? Have a suggestion for a fuzzing tool to add? Or just want to get in touch? I’d love to hear from you! You can also subscribe to my newsletter below to be notified when I update this article or publish new ones.