↑Supply Chain Security

appsec.guide β€” Fuzzing Chapter (Trail of Bits Testing Handbook)

title
appsec.guide β€” Fuzzing Chapter (Trail of Bits Testing Handbook)
type
summary
summary
Trail of Bits' Testing Handbook fuzzing chapter β€” terminology, the mutation-based evolutionary algorithm, fuzzer components, and a taxonomy of bug classes; entry point to language-specific subsections
tags
fuzzing, security, testing, reference, trail-of-bits
created
2026-05-12
updated
2026-05-12

The fuzzing chapter of appsec.guide β€” Trail of Bits' open Testing Handbook. The page itself is the chapter index and a foundational primer; the rest of the chapter splits into language-specific (C/C++, Rust, Go, Python, Ruby) and cross-language subsections.

This summary captures the foundational material here. Sub-chapters (libFuzzer, AFL++, cargo-fuzz, OSS-Fuzz, snapshot fuzzing, etc.) are separate ingests when needed.

Terminology (the vocabulary the rest of the chapter assumes)

  • SUT / target β€” System Under Test
  • Fuzzer β€” the program implementing the fuzzing algorithm; fuzzing the activity
  • Test case β€” a concrete input to the harness (bitstring, AST, structured value)
  • Harness β€” wraps the SUT, initializes it, integrates it into the testing environment
  • libFuzzer harness β€” a harness that exposes the LLVMFuzzerTestOneInput entry point
  • Fuzz test β€” the compiled binary containing harness + SUT
  • Campaign β€” one start-to-stop execution of the fuzzer
  • Corpus β€” the evolving set of test cases the campaign maintains
  • Seed corpus β€” the initial test cases the campaign starts from; individual entries are seeds
  • Fuzzing engine / runtime β€” the orchestrator (libFuzzer, AFL++, LibAFL, Honggfuzz)
  • Instrumentation β€” non-functional code added to the SUT to report coverage, sanitizer trips, comparisons, etc.
  • Code coverage β€” the metric most fuzzers use as their fitness function

The de facto algorithm

Modern coverage-guided fuzzers are evolutionary: maintain a population (corpus), schedule fit members, mutate them, keep offspring that show new fitness, repeat. Fitness is almost always code coverage. See coverage-guided-fuzzing for the concept page; the pseudocode from the handbook:

fn fuzz(corpus) {
  let bug_set = [];
  while let Some(test_case) = schedule(corpus) {
    let offspring = mutate(test_case);
    let observations = execute(offspring);

    if (is_interesting(observations)) { corpus.append(offspring); }
    if (is_bug(observations))         { bug_set.append(offspring); }
  }
  return bug_set;
}

The four customization points (schedule, mutate, execute, is_interesting / is_bug) are what fuzzer engines differ on. LibAFL's composition story is exactly "make all four traits."

What fuzzing finds

The handbook's bug-class taxonomy goes beyond the "memory corruption" reputation:

  • Crashes and panics β€” UAF, integer overflows, undefined behavior, buffer overflows, memory leaks
  • Invariant violations β€” business-logic / state-invariant bugs; requires stateful fuzzing (drive the SUT through a sequence of operations rather than one input)
  • Differentials β€” comparing implementations / platforms / versions; the technique behind most consensus-bug findings, see differential-fuzzing
  • Broken logical properties β€” round-trip (decode(encode(x)) = x), idempotence (f(f(x)) = f(x)), monotonicity, identity, commutativity, associativity
  • Race conditions β€” with thread-sanitizer / native race detector

Property checks (round-trip, idempotence, etc.) are the hook for property-based fuzzing β€” the same mental model as property-based testing (QuickCheck / Hypothesis) but driven by a coverage-guided mutator instead of a random generator.

Why this page is worth keeping in the wiki

The handbook is the right reference to point at when one of the wiki's fuzzing-adjacent pages needs background. It's open, author-bylined, vendor-neutral within fuzzing (the language-specific chapters cover libFuzzer, AFL++, cargo-fuzz, etc. β€” not just Trail of Bits tools), and reasonably current. Most other fuzzing primers online are either outdated AFL-era walkthroughs or vendor docs that don't generalize.

Sub-chapters (separate ingests when relevant)

  • C/C++ β€” libFuzzer, AFL++, LibAFL, techniques
  • Rust β€” cargo-fuzz, techniques
  • Go β€” covered by gosentry-go-fuzzing-fork in its own right; the handbook's Go section is older / pre-gosentry
  • Python and Ruby
  • Cross-language techniques β€” harnesses, dictionaries, ASan, environments, FAQ
  • OSS-Fuzz, snapshot fuzzing
  • Static analysis (CodeQL, Semgrep) is referenced from here but lives in a different chapter