Agent skill · Documentation

harness-writing

Techniques for writing effective fuzzing harnesses across languages. Use when creating new fuzz targets or improving existing harness code.

trailofbitsgithub.com/trailofbitsGitHub ↗
claude-codeCC-BY-SA-4.0
Install
npx skills add trailofbits/skills --skill harness-writing --agent claude-code

Same command for any agent — swap --agent for codex, cursor, copilot.

Facts
Files in the skill folder: 3
SKILL.md size: 20 KB
Bundled scripts: none
Path: plugins/testing-handbook-skills/skills/harness-writing/SKILL.md
Open the folder on GitHub →
Where it comes from
Stars: 6,426
Language: Python
Read our review of the source →

Weekly change comes from our own snapshots, not the repository page — it measures attention, not adoption.

Review
written from the skill's own SKILL.md · Aug 5, 2026

What it does

Provides concrete guidance for writing fuzzing harnesses that feed fuzzers with structured input, route to the SUT, and handle edge cases gracefully. It emphasizes selecting entry points, starting with minimal harnesses, adding input validation, using helpers like FuzzedDataProvider, and applying patterns for interleaved fuzzing, structure-aware fuzzing, and deterministic behavior.

How it works

  • Identifies entry points in codebases that accept external input or perform security-critical operations as targets for fuzzing.
  • Recommends starting with a minimal harness in C/C++ or Rust demonstrating a basic LLVMFuzzerTestOneInput or fuzz_target setup.
  • Advises adding input validation to reject inputs outside meaningful ranges while allowing malformed inputs to test harness robustness.
  • Describes structuring inputs for typed data via techniques like casting or using FuzzedDataProvider, and provides code samples for both approaches.
  • Covers various patterns: interleaved fuzzing across related operations, structure-aware fuzzing using Arbitrary in Rust, and using Protocol Buffers as an intermediate format for structured inputs.
  • Encourages testing and iteration with metrics like code coverage, execution speed, and crash reproducibility.
  • Presents practical harness rules to maintain determinism, avoid global state, prevent hangs, and ensure fast execution.
  • Includes tool-specific guidance for libFuzzer and AFL++, with sample harness signatures, compilation commands, and integration tips.

When to use it

Use when creating a new fuzz target for the first time or when fuzz campaigns have low coverage or unreproducible crashes, and when the target API requires structured inputs or multiple related functions should be tested together.

What it can touch

  • Mentions and uses the following tools and concepts explicitly: "LLVMFuzzerTestOneInput" (C/C++ harness entry), "fuzz_target!" (Rust harness macro), "FuzzedDataProvider" (helper for structured data), and protocols like Protocol Buffers as an intermediate format. It provides code blocks showing how to instantiate and use these components.

Caveats

  • Emphasizes not to call exit() in harnesses, to maintain determinism and enable rapid iteration.
  • Recommends avoiding heavy logging during fuzzing and resetting global state between iterations to improve reproducibility.
  • Notes limitations of certain approaches (e.g., Arbitrary crate behavior and its limitations with reverse serialization).
From the SKILL.md

# Writing Fuzzing Harnesses A fuzzing harness is the entrypoint function that receives random data from the fuzzer and routes it to your system under test (SUT). The quality of your harness directly determines which code paths get exercised and whether critical bugs are found. A poorly written harness can miss entire subsystems or produce non-reproducible crashes. ## Overview The harness is the bridge between the fuzzer's random byte generation and your application's API. It must parse raw bytes into meaningful inputs, call target functions, and handle edge cases gracefully. The most important part of any fuzzing setup is the harness—if written poorly, critical parts of your application may not be covered. ### Key Concepts | Concept | Description | |---------|-------------| | **Harness** | Function that receives fuzzer input and calls target code under test | | **SUT** | System Under Test—the code being fuzzed | | **Entry point** | Function signature required by the fuzzer (e.g., `LLVMFuzzerTestOneInput`) | | **FuzzedDataProvider** | Helper class for structured extraction of typed data from raw bytes | | **Determinism** | Property that ensures same input always produces same behavi

What's inside
Steps it walks through
  1. Overview
  2. Key Concepts
  3. When to Apply
  4. Quick Reference
  5. Step-by-Step
  6. Step 1: Identify Entry Points
  7. Step 2: Write Minimal Harness
  8. Step 3: Add Input Validation
  9. Step 4: Structure the Input
  10. Step 5: Test and Iterate
  11. Common Patterns
  12. Pattern: Beyond Byte Arrays—Casting to Integers
  13. Pattern: FuzzedDataProvider for Complex Inputs
  14. Pattern: Interleaved Fuzzing
Ships with 2 files
  • agents/openai.yaml
  • assets/trail-of-bits-mark.svg
Commands it runs
afl-fuzz -i seeds/ -o findings/ -- ./fuzz_target
cargo fuzz init
cargo fuzz add my_target
cargo +nightly fuzz run my_target
go-fuzz-build
go-fuzz -bin=./mypackage-fuzz.zip -workdir=fuzz
More from skills
All skills →
About this skill
What does the harness-writing skill do?

Techniques for writing effective fuzzing harnesses across languages. Use when creating new fuzz targets or improving existing harness code.

How do I install it?

Run `npx skills add trailofbits/skills --skill harness-writing --agent claude-code` — it drops the skill into your project so the agent can pick it up. Swap the --agent value for codex, cursor or copilot if you use one of those.

Where does this skill come from?

From trailofbits/skills, a repository with 6,426 stars. We read it straight from the repository tree rather than a submitted listing, so what you see here is what is actually published.

Is a popular skill a good skill?

Not necessarily. Stars measure attention, not adoption — a repository can trend for a week and be abandoned. That is why we show the weekly change from our own snapshots next to the total, instead of a single flattering number.

Keep going