Skip to main content

FuzzPrep

FuzzPrep is a CLI that takes the manual effort out of building C/C++ libraries for fuzzing while aiming to minimize LLM token cost. It detects the build system, builds the library, probes harness compilation to find linker dependencies, and writes artifacts that build and link the library against a harness.

Prerequisites

What FuzzPrep needs

  • Python 3.13 and uv.
  • git, to clone the target repository.
  • clang and clang++, the default compilers. --cc and --cxx select others.
  • libFuzzer's runtime, which clang links for the default -fsanitize=fuzzer harness flags. It is a separate package: libclang-rt-dev on Debian and Ubuntu, compiler-rt elsewhere. A plain apt install clang pulls it in as a recommended package, but an install that uses --no-install-recommends does not, so name it.
sudo apt update
sudo apt install -y git clang libclang-rt-dev

Common library build dependencies

A target brings its own build dependencies: the build system it uses, and the -dev packages it links against. FuzzPrep reports the packages a failed run is missing. The below script also installs a set that covers many targets — the four supported build systems, the usual codegen and archive utilities, and the libraries FuzzPrep knows how to identify from error traces:

./scripts/install_common_deps.sh

The list is not exhaustive. When a build fails on a dependency the script does not cover, install that dependency and run again.

Optional

  • Docker, for --environment oss-fuzz.
  • The claude or codex CLI, for agent repair. It is on by default; --no-agents turns it off and no CLI is then needed.
  • bear, for Make and Autotools targets built with --environment local. It captures compile_commands.json, which extract-features and generate-yaml read.
  • cmake, llvm-dev, libclang-20, and libclang-dev, which extract-features builds its Clang LibTooling parser against. With more than one LLVM installed, point CMAKE_PREFIX_PATH at the tree the clang on PATH belongs to.

The apt packages among these:

sudo apt install -y bear cmake llvm-dev libclang-dev libclang-20

Install

uv sync

Quickstart

Best practice: Run FuzzPrep in a container or disposable VM. FuzzPrep compiles and executes arbitrary build-system logic from the target library. Its agentic workflow may also write and execute build scripts, so it should be run in an isolated environment.

From a local checkout after uv sync:

# Clones the repository, builds it, verifies it, and writes `output/zlib/`.
uv run fuzzprep generate https://github.com/madler/zlib.git

To run FuzzPrep without cloning this repository:

uvx fuzzprep generate https://github.com/madler/zlib.git

Other useful flags include:

# Verify in the OSS-Fuzz Docker environment instead of on the host
uv run fuzzprep generate <REPO_URL> --environment oss-fuzz

# Turn off agent repair: a failed build then simply fails the run
uv run fuzzprep generate <REPO_URL> --no-agents

# Pass build-system configure options (repeat for more than one)
uv run fuzzprep generate <REPO_URL> --library-configure-arg=-DCARES_STATIC=ON

# Skip the from-scratch rebuild that validates an agent's repair, for a faster run
uv run fuzzprep generate <REPO_URL> --bypass-scratch-validation

# Use distinct library and final-harness instrumentation defaults
uv run fuzzprep generate <REPO_URL> --environment local \
  --cc clang --cxx clang++ \
  --library-cflags='-fsanitize=fuzzer-no-link,address' \
  --library-cxxflags='-fsanitize=fuzzer-no-link,address' \
  --harness-cflags='-fsanitize=fuzzer,address' \
  --harness-cxxflags='-fsanitize=fuzzer,address'

Agent repair is on by default and calls a paid network service. --agent claude (the default) or --agent codex selects the backend; --no-agents turns it off.

See uv run fuzzprep generate --help for the full set of options (custom output location, pinning a branch/tag/commit, a different base image, etc).

Adaptable builds

The generated build scripts let you supply your own toolchain and flags:

CC=afl-clang-fast CXX=afl-clang-fast++ \
CFLAGS=-fsanitize=address CXXFLAGS=-fsanitize=address \
  ./build_library.sh

When a run fails

FuzzPrep keeps its working state in .fuzzprep/<project>/: the workspace it built in, logs/ with the raw output of each phase, and stats.json. A failed run writes no output directory, but the library build artifacts stay in .fuzzprep/<project>/install/ if you want to debug the link line there. Add --log-level debug for more detail, or --quiet to hide the raw subprocess output while a phase runs.

What it does

  1. Detects the build system: CMake, Meson, Autotools, or Makefile.
  2. Builds the library with a deterministic script. If that build fails, an agent repairs it.
  3. Probes harness compilation to find transitive linker dependencies. If the probe fails, an agent repairs it.
  4. Writes the output directory <output>/<project>/.

Output

The output directory provides a reproducible OSS-Fuzz project and a standalone host build tree. docker build . works, and so does ./setup.sh && ./build_library.sh.

output/<project>/
├── Dockerfile             # OSS-Fuzz project files
├── project.yaml           # OSS-Fuzz project metadata
├── .dockerignore
├── setup.sh               # Script for repo clone + apt dependencies
├── build.sh               # Builds the library and compiles the provided harness
├── build_library.sh       # build and install the library into install/
├── compile_harness.sh     # compile and link one harness source
├── compile_harnesses.sh   # compile every source in harness_source/ into out/
├── harness_source/        # source code of all harnesses
├── install/               # the library this run built
├── compile_commands.json  # captured compile commands
├── stats.json             # what this run did: durations, agent use, status
└── README.md              # what this run verified, and how to run it

harness_source/ starts with a stub — an LLVMFuzzerTestOneInput with a // TODO: Add fuzzing logic body. FuzzPrep proves the harness compiles and links against the library; writing the fuzzing logic is yours.

Environments

--environment selects where this run builds and verifies. It does not change what is generated: the output directory always holds both setups. The generated README.md records which of the two this run exercised.

  • local — build and verify on the host.
  • oss-fuzz — build and verify in an OSS-Fuzz compatible Docker container, then prove the generated Dockerfile builds from scratch.

Neither environment isolates the target's build from your machine well enough to trust it. Run both inside a VM or an isolated machine.

Other commands

generate produces a compile_commands.json file that two follow-on commands consume, to extract the library's API surface (extract-features) and to produce an OSS-Fuzz-Gen compatible YAML input (generate-yaml).

uv run fuzzprep extract-features <BUILD_PATH>   # -> features.json (run this first)
uv run fuzzprep generate-yaml <BUILD_PATH>      # -> <project>.yaml

extract-features runs a Clang LibTooling-based parser over every header and source file in compile_commands.json. It writes <BUILD_PATH>/features.json, a structured inventory of the library's C/C++ declarations:

  • functions — name, return type, parameters, full signature, declaring header, and whether it is public API (declared in a header, not static)
  • typedefs — name, underlying type, declaring header
  • macros — name, object- or function-like, parameters (if function-like), value, declaring header
  • enums — name (if any), enumerators with their values, declaring header
  • records — structs and unions: name (if any), kind, fields, declaring header
  • warnings — non-fatal problems found during the parse

generate-yaml reads features.json and keeps only the public functions. To get finer-grained output, name one or more headers and it keeps only the functions those headers declare:

uv run fuzzprep generate-yaml <BUILD_PATH> zlib.h zconf.h

Run uv run fuzzprep --help for details.

Security

FuzzPrep clones and builds arbitrary third-party repositories, which runs their build systems on your machine, and it hands a repair agent write access to the run's workspace.

Run it in a VM or on a dedicated machine you can wipe, whatever --environment you pick. A container shares the host kernel and is not a boundary that holds against code written to break out of one, so --environment oss-fuzz reduces the blast radius of an ordinary build but does not contain a hostile one. --no-agents turns agent repair off.

SECURITY.md has the full threat model and tells you how to report a vulnerability.

Contributing

See CONTRIBUTING.md for the local setup, the checks a pull request must pass, and what each pytest marker needs. Participation is governed by the Code of Conduct.

License

FuzzPrep is licensed under Apache-2.0.

The feature_extractor tool that extract-features builds links cJSON and the LLVM/Clang libraries. THIRD_PARTY_NOTICES.md records their licenses and the notices that apply if you redistribute that binary.

Some files under tests/real_harnesses/ come from upstream projects and keep their own licenses; that directory's README records the provenance of each one.

Metadata

Release files for fuzzprep 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fuzzprep 0.1.0
File Size Uploaded
fuzzprep-0.1.0.tar.gz 91.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fuzzprep 0.1.0
File Interpreter ABI Platform
fuzzprep-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 212.5 kB

Release files / fuzzprep-0.1.0.tar.gz

Download URL fuzzprep-0.1.0.tar.gz
Size 91.9 kB
Tags Source
SHA-256 checksum
How to use checksums
857fe41a13deddfecf3a33a5be81e8b380c574166c179c3bd3cf03d4262d5df5
BLAKE2b-256 checksum
How to use checksums
f3e463a2e3db0ede8f0694c0f1d14c733ff6efa93902523eb86187ccc7970dd9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.

Transparency log

Release files / fuzzprep-0.1.0-py3-none-any.whl

Download URL fuzzprep-0.1.0-py3-none-any.whl
Size 120.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f93e7841a1f3d8bad5f906b514aa6694b9ad7601eb833b164a8951e027c7095c
BLAKE2b-256 checksum
How to use checksums
8acd157676fc966a07195ad2fb4222baff2a131c8e92db1147551c725a76c859
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page