TNO developed WuppieFuzz, a coverage-guided REST API fuzzer developed on top of LibAFL, targeting a wide audience of end-users, with a strong focus on ease-of-use, explainability of the discovered flaws and modularity. WuppieFuzz supports all three settings of testing (black box, grey box and white box).
[!NOTE]
For a quick, follow-along guidance please follow the tutorial!
WuppieFuzz has been featured in:
If you want to cite WuppieFuzz in academic work, please use the preferred publication listed in CITATION.cff:
Rooijakkers, T., Nijsten, A., Daniele, C., Weitenberg, E., Groenewegen, R., & Melissen, A. (2026). WuppieFuzz: Coverage-Guided, Stateful REST API Fuzzing. In Proceedings of the 12th International Conference on Information Systems Security and Privacy (ICISSP), Volume 2, 221-231. SciTePress. https://doi.org/10.5220/0000217100004061
WuppieFuzz is licensed under Apache-2.0; see LICENSE.
Third-party license notices are listed in THIRD_PARTY_NOTICES.
For quick installation of WuppieFuzz for popular operating systems (MacOS,
Windows, Linux) see releases or use brew install wuppiefuzz
To build the project you need to install the following dependencies and tooling
sudo apt install build-essentialsudo apt install pkg-configcurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shBefore running WuppieFuzz, you have to start your (instrumented) target application.
Additionally, you must supply WuppieFuzz with an OpenAPI-specification so it knows how to generate and mutate its requests. For help on the command line arguments, use the following:
$ cargo run -- --help # shows help for required parameters and flags
Usage: wuppiefuzz [OPTIONS] [OPENAPI_SPEC.YAML]
...
For example, to run WuppieFuzz against a Java target with the JaCoCo agent attached, you specify its OpenAPI file (containing the URL the target is running on in the API specification). In addition, you specify that the coverage format is JaCoCo, and give the classes directory as follows:
cargo run -- fuzz openapi.yaml --coverage-format jacoco --jacoco-class-dir ../Targets/app/target/classes/
If you want to use a configuration file instead of/in combination with command
line arguments, you can use the flag --config <CONFIG_FILE>. In case you use
command line arguments in combination with a configuration file, command line
arguments take precedence.
The configuration file should be a yaml file and contain a line for each command line argument you want to specify, for example:
coverage_format: jacoco
output_format: human-readable
source_dir: "/swagger-petstore/src/main/java"
jacoco_class_dir: "/swagger-petstore/target"
timeout: 20
An example run command could in this case be:
$ cargo run -- fuzz --config=config.yaml --report --coverage-host=localhost:6300 --timeout=10 ./openapi.yaml
This line would combine the arguments from the command line and from the config
file. Since the flag --timeout is specified in both, the timeout specified in
the command line (10 seconds) will take precedence.
In the directory example_configs/ you will find two example config files to
use for generating coverage reports with JaCoCo for Java code and for generating
coverage reports with LCOV for Python code.
When you WuppieFuzz with the --report flag, a subdirectory is made inside
reports/ with a timestamp as its name. All supported coverage report(s) are
written into this subdirectory. There are two types of coverage reports:
On top of that a database is filled with all request information related to your fuzzing campaign. This database can be visualised and explored through the Grafana dashboard.
For more information on each of these, see the READMEs in these directories.
By default, WuppieFuzz vendors its C dependencies (OpenSSL, SQLite, Z3) so that
a regular cargo build works out of the box. For faster compilation during
development, you can disable all vendored dependencies and link against
system-installed libraries instead.
[!NOTE] The
z3crate requires Z3 4.15+, which is newer than the version shipped by most Linux distribution package managers. Install Z3 via Homebrew (brew install z3) to get a compatible version.
Install the following libraries on your system:
Debian/Ubuntu:
sudo apt install libssl-dev libsqlite3-dev
brew install z3 # apt's libz3-dev is too old; use Homebrew instead
On Linux, Homebrew installs to a non-standard path. Add its library directory to your environment so the compiler and runtime linker can find Z3:
eval "$(brew shellenv)"
export LIBRARY_PATH="$(brew --prefix z3)/lib:$LIBRARY_PATH"
export LD_LIBRARY_PATH="$(brew --prefix z3)/lib:$LD_LIBRARY_PATH"
[!TIP] Add the lines above to your
~/.bashrcor~/.zshrcto make them permanent.
Fedora (42+):
sudo dnf install openssl-devel sqlite-devel z3-devel
macOS (Homebrew):
brew install openssl sqlite z3
The repository includes cargo aliases in .cargo/config.toml that build with
--no-default-features, linking against all system libraries:
cargo dev-build # build without vendored dependencies
cargo dev-run -- <args> # run without vendored dependencies
cargo dev-test # test without vendored dependencies
cargo doc --no-deps to generate documentation from comments in the source
code. The main page of the documentation will be
target/doc/wuppiefuzz/index.html
$ claude mcp add WuppieFuzz \
-- python -m otcore.mcp_server <graph>