Testland
Browse all skills & agents

ossfuzz-integration

Author and submit a project to Google OSS-Fuzz - the open-source continuous fuzzing service that runs libFuzzer / AFL++ / Honggfuzz campaigns on Google infrastructure 24x7. Covers the project.yaml + Dockerfile + build.sh contract, the $OUT/$WORK conventions, supported languages + sanitisers, seed-corpus + dictionary submission, the OSS-Fuzz Build Status dashboard, and the disclosure SLA (issues filed in Monorail with 90-day deadline). Use to offload long-running fuzz campaigns to dedicated infrastructure rather than self-hosting.

Install with skills.sh (any agent)

npx skills add testland/qa --skill ossfuzz-integration
View source

ossfuzz-integration

Overview

OSS-Fuzz (per google.github.io/oss-fuzz (opens in new window)) runs libFuzzer / AFL++ / Honggfuzz campaigns 24x7 on Google Cloud across multiple sanitiser configurations (ASan, UBSan, MSan), auto-files bug reports with crash reproducers, and tracks fix status with a 90-day disclosure SLA.

For corpus discipline see corpus-management-reference; for sanitiser pairing see sanitiser-integration-reference.

When to use

  • Production-grade fuzzing of an open-source library - OSS-Fuzz runs continuously, finds bugs you'd miss with periodic CI fuzz.
  • Established projects with mature fuzz targets - OSS-Fuzz wants proven harnesses, not experimental ones.
  • Pre-disclosure pipeline for security-sensitive libraries - OSS-Fuzz files in Monorail with structured severity + 90-day deadline.

For commercial / closed-source projects: ClusterFuzz (the open-source backend behind OSS-Fuzz) can be self-hosted.

How to use

  1. Confirm the project qualifies: open-source, with a mature harness (>=10k execs/sec locally) rather than an experimental one.
  2. Create projects/<project-name>/ with project.yaml, Dockerfile, and build.sh per references/project-contract.md.
  3. Build and validate locally: infra/helper.py build_image, then build_fuzzers --sanitizer address, then check_build.
  4. Ship a seed corpus (<target>_seed_corpus.zip) and, for structured formats, a dictionary (<target>.dict) beside the target.
  5. Open a pull request to github.com/google/oss-fuzz; the OSS-Fuzz team reviews security, scope, and maintainer verification.
  6. On merge, watch the Build Status dashboard and triage Monorail issues (reproduce with infra/helper.py reproduce) within the 90-day disclosure deadline.

Authoring

Each project lives at projects/<project-name>/ with three files: project.yaml (metadata - language, fuzzing_engines, sanitizers, contacts), a Dockerfile that builds the fuzz targets on base-builder, and a build.sh that produces $OUT/<fuzz_target> plus seed corpora. Verify locally with infra/helper.py before opening the PR.

Full field-by-field contract, file templates, and the local-testing commands: references/project-contract.md.

Running

Submitting a new project

  1. Open a pull request to github.com/google/oss-fuzz (opens in new window) adding projects/<project-name>/.
  2. OSS-Fuzz team reviews (security + scope + maintainer verification).
  3. On merge, the project enters the 24x7 fuzzing rotation.
  4. Build status appears at oss-fuzz-build-logs.storage.googleapis.com (opens in new window).

Receiving findings

Bugs are filed in Monorail (issues.oss-fuzz.com) with:

  • Crash reproducer attached
  • Sanitiser output
  • Severity classification
  • Auto-CC to project contacts
  • 90-day disclosure deadline (per Google's standard disclosure policy)

After the 90-day deadline, unfixed bugs become public.

Updating an existing project

Fork -> modify -> PR. Common changes:

  • New fuzz targets (additional *.cc + build.sh updates)
  • Refreshed seed corpora
  • Sanitiser additions (turn on MSan once dependencies are instrumented)
  • Maintainer contact updates

Parsing results

OSS-Fuzz crash artefact format matches libFuzzer's. The Monorail issue includes:

  • Crash reproducer: download from Monorail attachment; reproduce locally:
    python infra/helper.py reproduce <project-name> fuzz_target_1 <crash-file>
    
  • Sanitiser output: the report stack + alloc / free sites
  • Coverage info: which lines were hit by the input

Feed this to bug-report-from-failure for downstream bug-tracker filing.

Worked example

A maintainer wants continuous fuzzing for a JPEG decoder library. They add projects/jpeg-decoder/ with language: c, fuzzing_engines: [libfuzzer, afl], sanitizers: [address, undefined], and primary_contact set. build.sh compiles the decoder and links decompress_fuzzer against $LIB_FUZZING_ENGINE, then copies decompress_fuzzer_seed_corpus.zip (sample JPEGs) to $OUT. Locally, python infra/helper.py check_build jpeg-decoder passes. They open the PR; OSS-Fuzz merges it about a week later. A few days in, Monorail files a heap-buffer-overflow in the Huffman decoder with an attached reproducer. They run python infra/helper.py reproduce jpeg-decoder decompress_fuzzer crash-abc123, confirm the bug, patch it, and the issue closes before the 90-day deadline.

Anti-patterns

Anti-patternWhy it failsFix
Submitting an experimental harnessSlow path discovery wastes OSS-Fuzz computeMature harness locally first; ≥10k execs/sec
No seed corpusWastes first weeks rediscovering shallow inputsSubmit <target>_seed_corpus.zip with the project
No dictionary for structured formatsSlow grammar discoverySubmit <target>.dict
Fuzz target builds incompletely with MSanBuild matrix slot wastedSkip MSan in project.yaml until dependencies instrumented
Stale main_repo URLOSS-Fuzz pulls from wrong branchKeep main_repo current
Missing primary_contact / auto_ccsBug reports go nowhereAlways set contact emails
Fix-then-ignoreDisclosure deadline still applies; the bug becomes public 90 days laterFix within deadline OR request extension

Limitations

  • Open-source only. Closed-source projects use ClusterFuzz self-hosted, not OSS-Fuzz.
  • Maintainer review required. New project PRs need approval - cycle time 1-4 weeks.
  • Severity classification is automated. OSS-Fuzz heuristic may misclassify; maintainer can re-tag in Monorail.
  • Resource allocation is opaque. Google decides how much compute to allocate per project.
  • Builds break on dependency drift. When upstream dependencies change, build.sh may break - monitor the build status page.

References

OSS-Fuzz project contract

View source (opens in new window)

OSS-Fuzz project contract

The projects/<project-name>/ file contract - project.yaml, Dockerfile, build.sh - plus how to verify it locally before submitting.

Project layout in OSS-Fuzz repo

Per the OSS-Fuzz docs at google.github.io/oss-fuzz/getting-started/new-project-guide (opens in new window), each project lives at projects/<project-name>/ and contains:

projects/<project-name>/
  project.yaml      # metadata: language, fuzzing_engines, sanitizers, primary_contact
  Dockerfile        # builds the fuzz targets
  build.sh          # produces $OUT/<fuzz_target_1> + seed corpora

project.yaml

homepage: "https://example.com/project"
language: c++   # or c, rust, go, python, jvm, swift
fuzzing_engines:
  - libfuzzer
  - afl
  - honggfuzz
sanitizers:
  - address
  - undefined
  - memory
primary_contact: "maintainer@example.com"
auto_ccs:
  - "security@example.com"
main_repo: "https://github.com/example/project"

Per the OSS-Fuzz docs, language drives which build template is used; fuzzing_engines × sanitizers enumerates the build matrix (libFuzzer + ASan, libFuzzer + UBSan, libFuzzer + MSan, AFL + ASan, etc.).

Dockerfile

FROM gcr.io/oss-fuzz-base/base-builder

# Install dependencies
RUN apt-get update && apt-get install -y \
    cmake ninja-build

# Clone the source
RUN git clone --depth=1 https://github.com/example/project /src/project
WORKDIR /src/project

# Copy build script + seed corpus
COPY build.sh fuzz_target_1.cc fuzz_target_1_seed_corpus.zip $SRC/

WORKDIR /src/project

Per OSS-Fuzz docs, the base image (base-builder) provides clang + libFuzzer + afl-clang-fast + sanitisers preinstalled. Language-specific base images exist (base-builder-rust, base-builder-go, base-builder-jvm, etc.).

build.sh

#!/bin/bash -eu
# OSS-Fuzz sets $OUT, $WORK, $CC, $CXX, $CFLAGS, $CXXFLAGS, $LIB_FUZZING_ENGINE

# Build the library
cd /src/project
mkdir -p build && cd build
cmake -G Ninja .. \
    -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_SHARED_LIBS=OFF
ninja

# Build fuzz target
$CXX $CXXFLAGS \
    -I/src/project/include \
    /src/fuzz_target_1.cc \
    /src/project/build/libproject.a \
    $LIB_FUZZING_ENGINE \
    -o $OUT/fuzz_target_1

# Seed corpus
cp /src/fuzz_target_1_seed_corpus.zip $OUT/fuzz_target_1_seed_corpus.zip

# Dictionary (optional)
cp /src/fuzz_target_1.dict $OUT/fuzz_target_1.dict

Per OSS-Fuzz docs:

  • $OUT is where final fuzz target binaries + seed corpora must land
  • $CXX / $CXXFLAGS are pre-configured with the correct sanitiser + libFuzzer flags for the active build configuration
  • $LIB_FUZZING_ENGINE links the libFuzzer / AFL driver
  • Seed corpora ship as <target>_seed_corpus.zip
  • Dictionaries ship as <target>.dict

Local testing

Before submitting, verify locally with the helper script:

git clone https://github.com/google/oss-fuzz
cd oss-fuzz
python infra/helper.py build_image <project-name>
python infra/helper.py build_fuzzers --sanitizer address <project-name>
python infra/helper.py check_build <project-name>
python infra/helper.py run_fuzzer <project-name> fuzz_target_1

Per the OSS-Fuzz docs, check_build validates the harness will run on Google infrastructure.

Related skills

afl-plus-plus

Author and run AFL++ - out-of-process coverage-guided fuzzer (a community fork of Google's original AFL with improved mutations and instrumentation). Covers afl-cc / afl-clang-fast instrumented build, afl-fuzz invocation, parallel master/slave (-M / -S), dictionary support (-x), QEMU mode (-Q) for binaries without source, output structure (queue / crashes / hangs), crash minimisation (afl-tmin), corpus minimisation (afl-cmin), crash filename triage, and CI integration. Use for fuzzing standalone binaries (file processors, command-line tools) where libFuzzer's in-process model doesn't fit; for cross-fuzzer corpus strategy see corpus-management-reference.

atheris-python-fuzzing

Author and run Atheris - Google's Python coverage-guided fuzzer built on libFuzzer. Covers pip installation, atheris.Setup + atheris.Fuzz invocation, TestOneInput(data: bytes) target signature, FuzzedDataProvider for structured input, instrument_imports() / instrument_func decorators for coverage instrumentation, and libFuzzer-passthrough flags (-atheris_runs, -max_total_time, -dict). Use for fuzzing Python libraries - also supports CPython native-extension fuzzing.

cargo-fuzz-rust

Author and run cargo-fuzz - Rust fuzzing via libFuzzer with cargo integration. Covers `cargo install cargo-fuzz`, `cargo fuzz init` + `cargo fuzz add {target}` for harness scaffolding, the `fuzz_target!` macro for entry-point declaration, the `Arbitrary` trait for structured input mutation, and `cargo fuzz run` invocation. Requires Rust nightly. Use for fuzz testing Rust libraries - cargo-fuzz wraps libFuzzer with native Rust ergonomics.

corpus-management-reference

Pure-reference catalog of fuzz-corpus management practices. Defines what a corpus is (seed corpus + evolved corpus saved by the fuzzer), corpus directory layout per libFuzzer / AFL++ / Go native / cargo-fuzz / OSS-Fuzz, the canonical crash-artefact naming (crash-{sha1} / leak-{sha1} / timeout-{sha1}), seed corpus construction strategies (sample-from-prod, sample-from-test-fixtures, from-spec-keywords), corpus minimisation, dictionary files, and the OSS-Fuzz integration corpus sync. Use as the corpus-discipline reference when building a fuzz target or maintaining a long-running fuzz campaign.

crash-triage-reference

Pure-reference catalog for manually triaging individual fuzzer crash artifacts - reading ASan, UBSan, and MSan output; classifying findings as LIKELY-EXPLOITABLE, MEDIUM, or BENIGN; deduplicating by stack-hash; and minimizing reproducers with -minimize_crash. Use when you need to understand what a specific crash means, build exploitability intuition, or manually work a small set of findings. For automated bulk triage across a full artifact directory, run automated findings triage instead.

fuzz-tool-selector

Routes a fuzz-target authoring task to the right fuzzer for the detected language and build type. Decision tree: C/C++ → libfuzzer-cpp + afl-plus-plus; Rust → cargo-fuzz-rust (or libfuzzer-cpp via FFI); Go → go-native-fuzzing; Python → atheris-python-fuzzing; JVM → jazzer-jvm-fuzzing; closed-source binary → afl-plus-plus in QEMU mode; mature open-source project → ossfuzz-integration. Use when a project needs coverage-guided fuzzing and no fuzzer has been chosen for its language or toolchain yet.

go-native-fuzzing

Author and run Go's native fuzzing (Go 1.18+) - coverage-guided fuzzing built into the standard testing package via FuzzXxx functions. Covers f.Add seed-corpus declaration, f.Fuzz callback signature with typed parameters, testdata/fuzz/{FuzzXxx}/ directory layout for seeds + regression cases, the -fuzz flag for `go test`, and CI integration via short smoke runs. Use for fuzz testing Go libraries - Go's native approach integrates seamlessly with standard `go test` rather than requiring a separate toolchain like AFL++.

jazzer-jvm-fuzzing

Author and run Jazzer - Code Intelligence's JVM coverage-guided fuzzer built on libFuzzer. Covers Maven / Gradle / standalone JAR installation, the @FuzzTest annotation (JUnit 5 integration), typed parameter mutation (String, primitives, byte[]), built-in JVM sanitisers (SSRF / path traversal / OS command injection / deserialization gadget / ReDoS), and the JAZZER_FUZZ=1 env var to switch between regression and fuzzing modes. Use for fuzz testing Java / Kotlin libraries - particularly effective against parsing, deserialization, and HTTP-handling code.

libfuzzer-cpp

Author and run LLVM libFuzzer for C/C++ - in-process coverage-guided fuzzing. Covers harness authoring (LLVMFuzzerTestOneInput entry point), build with -fsanitize=fuzzer,address,undefined, runtime flags (-max_total_time, -runs, -dict, -fork, -workers), corpus + crash-artefact handling, and CI integration. Use for libraries / parsers / decoders in C/C++ where in-process fuzzing of a function is the right scope. Compose with ASan + UBSan from sanitiser-integration-reference and corpus discipline from corpus-management-reference.

sanitiser-integration-reference

Pure-reference catalog of compiler sanitisers used with fuzz testing - AddressSanitizer (ASan), UndefinedBehaviorSanitizer (UBSan), MemorySanitizer (MSan), ThreadSanitizer (TSan), and LeakSanitizer (LSan). Explains what each detects, compatibility (can ASan + UBSan combine? - yes; ASan + MSan? - no), build flags, runtime options (ASAN_OPTIONS / UBSAN_OPTIONS env vars), and the typical ~2x slowdown per ASan. Use to pick the right sanitiser per fuzz target, configure the build, and interpret crash reports.