Testing Handbook Skills

Testing Handbook Skills

Testing Handbook skills: fuzzers, static analysis, sanitizers

Category: development Source: trailofbits/skills

What Is This?

Overview

The Trail of Bits Testing Handbook is a comprehensive collection of security-focused testing techniques developed by one of the most respected security research firms in the industry. It covers three primary pillars of modern software security testing: fuzzing, static analysis, and sanitizers. Each technique targets a different class of vulnerabilities and complements the others to provide thorough coverage of a codebase.

This handbook distills years of practical experience from security audits, vulnerability research, and software hardening engagements. Rather than presenting abstract theory, it provides actionable guidance on integrating these tools into real development workflows. Engineers can apply these techniques during development, in CI pipelines, or as part of dedicated security review cycles.

The skills derived from this handbook are particularly valuable because they address the gap between writing code and writing secure code. Many developers understand unit testing but have limited exposure to the adversarial mindset required for security testing. This handbook bridges that gap with concrete tooling and methodology.

Who Should Use This

  • Security engineers who perform code audits and need structured tooling frameworks for vulnerability discovery
  • Software developers who want to integrate security testing into their daily workflow and CI pipelines
  • DevSecOps practitioners responsible for building automated security gates in deployment pipelines
  • Researchers studying memory safety, undefined behavior, and input validation vulnerabilities
  • Open source maintainers who need cost-effective automated testing to catch bugs before public disclosure
  • Engineering teams adopting Rust, C, or C++ who need sanitizer and fuzzer configurations specific to those languages

Why Use It?

Problems It Solves

  • Manual code review misses entire classes of bugs that automated fuzzing and static analysis can surface reliably
  • Memory corruption vulnerabilities such as buffer overflows and use-after-free errors often go undetected without sanitizer instrumentation
  • Development teams lack standardized guidance on which tools to use, how to configure them, and how to interpret their output
  • Security testing is often deferred to late in the development cycle, making fixes expensive and disruptive
  • Fuzzing campaigns frequently produce low-quality results when engineers lack knowledge of corpus management and coverage-guided strategies

Core Highlights

  • Covers AFL++, libFuzzer, and Honggfuzz with configuration examples for each
  • Provides sanitizer setup for AddressSanitizer, UndefinedBehaviorSanitizer, and MemorySanitizer
  • Includes static analysis guidance using CodeQL, Semgrep, and clang-tidy
  • Demonstrates how to write effective fuzz targets that maximize code coverage
  • Explains triage workflows for reducing and reproducing crashes found during fuzzing
  • Covers continuous fuzzing integration with OSS-Fuzz and ClusterFuzz
  • Addresses language-specific considerations for C, C++, Go, and Rust

How to Use It?

Basic Usage

A minimal libFuzzer target in C looks like the following:

#include <stdint.h>
#include <stddef.h>

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Pass fuzzer-controlled input to the function under test
    parse_input(data, size);
    return 0;
}

Compile and run with AddressSanitizer enabled:

clang -fsanitize=address,fuzzer -o fuzz_target fuzz_target.c
./fuzz_target -max_total_time=3600 corpus/

Specific Scenarios

Scenario 1: Hardening a parser. When testing a file format parser, create a seed corpus from valid sample files, then run libFuzzer with coverage feedback. The fuzzer will mutate inputs to explore edge cases in parsing logic that manual tests would never reach.

Scenario 2: CI integration with Semgrep. Add a Semgrep scan step to your pipeline to catch insecure patterns before merge:

semgrep --config=p/security-audit --error src/

Real-World Examples

A network protocol implementation can be fuzz-tested by wrapping the deserialization function in a libFuzzer harness, then running it against a corpus of captured packets. Crashes indicate memory safety issues that could be exploited remotely.

A cryptographic library benefits from UndefinedBehaviorSanitizer during testing to catch integer overflows and misaligned memory accesses that produce incorrect results without crashing.

When to Use It?

Use Cases

  • Pre-release security hardening of libraries that process untrusted input
  • Continuous background fuzzing in CI for projects with active development
  • Security audits requiring evidence of automated testing coverage
  • Onboarding engineers to security testing practices with structured reference material
  • Evaluating third-party dependencies for memory safety issues

Important Notes

Requirements

  • A Linux or macOS build environment with Clang or GCC installed
  • Familiarity with the target codebase and its build system
  • Sufficient compute resources for long-running fuzzing campaigns

Usage Recommendations

Do:

  • Start fuzzing early in the development cycle when fixing bugs is cheapest
  • Maintain and grow your seed corpus over time
  • Triage and fix crashes promptly to keep the fuzzing signal meaningful

Do not:

  • Run sanitizer-instrumented binaries in production environments
  • Ignore low-severity findings, as they often chain into critical vulnerabilities
  • Rely solely on static analysis without dynamic testing to validate findings