Official agent skill

Fuzzing Harness Design

by trailofbits in trailofbits/skills

Guides writing and improving fuzzing harnesses for C, C++ and Rust so random byte input gets translated into structured, reproducible test cases for the target code.

OfficialCC-BY-SA-4.0Auto-check passedSecurity

Install Fuzzing Harness Design

skills CLI
$ npx skills add trailofbits/skills --skill harness-writing -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install trailofbits/skills harness-writing --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/trailofbits/skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/plugins/testing-handbook-skills/skills/harness-writing .claude/skills/harness-writing && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
harness-writing
GitHub stars
7.4k
Used in
1 other repo
Token cost
~5.3k tokens
SKILL.md length
1,693 words
Files
3 (incl. assets)
Skills in repo
79
Repo updated
First seen
Licence
CC-BY-SA-4.0

At a glance

Guides writing and improving fuzzing harnesses for C, C++ and Rust so random byte input gets translated into structured, reproducible test cases for the target code.

  • Works in 5 steps: Identify Entry Points → Write Minimal Harness → Add Input Validation → …
  • Writing a first fuzz harness for a C, C++ or Rust library
  • SKILL.md covers Overview, When to Apply, Quick Reference and Step-by-Step, plus 7 more sections
  • Calls cargo

What it does

This skill treats the harness, the entry point that receives fuzzer bytes and calls the system under test, as the single biggest factor in whether a fuzzing campaign finds real bugs. It defines key terms such as the system under test, the fuzzer's required entry-point signature like LLVMFuzzerTestOneInput or fuzz_target!, FuzzedDataProvider for turning raw bytes into typed values, determinism, and interleaved fuzzing where one harness exercises several operations based on its input.

It applies when a fuzz target is being written for the first time, when a running campaign has low coverage or finds nothing, when crashes do not reproduce, or when the target's API needs structured rather than raw input; it is skipped when an existing well-tested harness or automatic harness generation already covers the target. A quick-reference table gives the minimal C++ and Rust harness signatures, a size-validation guard, and FuzzedDataProvider calls for consuming typed values and strings.

The step-by-step guidance begins by identifying entry points in the target API before structuring how bytes map onto arguments, and the skill ships as a plugin asset bundle with a Trail of Bits mark.

When your agent uses it

  • Writing a first fuzz harness for a C, C++ or Rust library
  • Fixing a fuzzing campaign that finds no bugs or has low coverage
  • Debugging a fuzzer crash that will not reproduce
  • Deciding whether to fuzz several related functions together with one harness

Example prompts

  • “Write a libFuzzer harness for this C++ parsing function using FuzzedDataProvider.”
  • “Our fuzz_target! harness in Rust isn't finding anything. Review it for coverage gaps.”
  • “This crash doesn't reproduce outside the fuzzer. Help me find the non-determinism in the harness.”
  • “Combine fuzzing for these three related API functions into one interleaved harness.”

Requirements

  • A C, C++ or Rust codebase with a fuzzing toolchain such as libFuzzer or cargo-fuzz

Workflow steps

5 steps, taken from the step headings in SKILL.md.

  1. Identify Entry Points
  2. Write Minimal Harness
  3. Add Input Validation
  4. Structure the Input
  5. Test and Iterate

What it can do on your machine

Read from SKILL.md and the folder at commit 82fe822. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • cargo

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • github.com
    • llvm.org
    • rust-fuzz.github.io
    • youtube.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Fuzzing Harness Design loads about 5.3k tokens when it runs. Until then it costs about 110 tokens; SKILL.md has 1,693 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~110
When it runs · the whole SKILL.md, loaded when a task matches
~5.3k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from trailofbits/skills at commit 82fe822, republished under its CC-BY-SA-4.0 licence (© trailofbits). 1,693 words, ~5,306 tokens.

Download SKILL.mdSave it as .claude/skills/harness-writing/SKILL.md (or your agent's skills folder). This skill also uses 2 other files; get the full folder from GitHub.
name
harness-writing
description
Designs and improves fuzzing harnesses for C/C++ and Rust. Covers mapping raw bytes onto a target API, generating structured inputs, avoiding non-determinism and false crashes, and deciding what to fuzz together. Use when writing a first LLVMFuzzerTestOneInput or fuzz_target! harness, when a campaign finds nothing or reports crashes that will not reproduce, or when the target API needs structured rather than raw input.
type
technique

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
ConceptDescription
HarnessFunction that receives fuzzer input and calls target code under test
SUTSystem Under Test—the code being fuzzed
Entry pointFunction signature required by the fuzzer (e.g., LLVMFuzzerTestOneInput)
FuzzedDataProviderHelper class for structured extraction of typed data from raw bytes
DeterminismProperty that ensures same input always produces same behavior
Interleaved fuzzingSingle harness that exercises multiple operations based on input

When to Apply

Apply this technique when:

  • Creating a new fuzz target for the first time
  • Fuzz campaign has low code coverage or isn't finding bugs
  • Crashes found during fuzzing are not reproducible
  • Target API requires complex or structured inputs
  • Multiple related functions should be tested together

Skip this technique when:

  • Using existing well-tested harnesses from your project
  • Tool provides automatic harness generation that meets your needs
  • Target already has comprehensive fuzzing infrastructure

Quick Reference

TaskPattern
Minimal C++ harnessextern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
Minimal Rust harness`fuzz_target!(
Size validationif (size < MIN_SIZE) return 0;
Cast to integersuint32_t val = *(uint32_t*)(data);
Use FuzzedDataProviderFuzzedDataProvider fuzzed_data(data, size);
Extract typed data (C++)auto val = fuzzed_data.ConsumeIntegral<uint32_t>();
Extract string (C++)auto str = fuzzed_data.ConsumeBytesWithTerminator<char>(32, 0xFF);

Step-by-Step

Step 1: Identify Entry Points

Find functions in your codebase that:

  • Accept external input (parsers, validators, protocol handlers)
  • Parse complex data formats (JSON, XML, binary protocols)
  • Perform security-critical operations (authentication, cryptography)
  • Have high cyclomatic complexity or many branches

Good targets are typically:

  • Protocol parsers
  • File format parsers
  • Serialization/deserialization functions
  • Input validation routines
Step 2: Write Minimal Harness

Start with the simplest possible harness that calls your target function:

C/C++:

cpp
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    target_function(data, size);
    return 0;
}

Rust:

rust
#![no_main]
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    target_function(data);
});
Step 3: Add Input Validation

Reject inputs that are too small or too large to be meaningful:

cpp
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Ensure minimum size for meaningful input
    if (size < MIN_INPUT_SIZE || size > MAX_INPUT_SIZE) {
        return 0;
    }
    target_function(data, size);
    return 0;
}

Rationale: The fuzzer generates random inputs of all sizes. Your harness must handle empty, tiny, huge, or malformed inputs without causing unexpected issues in the harness itself (crashes in the SUT are fine—that's what we're looking for).

Step 4: Structure the Input

For APIs that require typed data (integers, strings, etc.), use casting or helpers like FuzzedDataProvider:

Simple casting:

cpp
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    if (size != 2 * sizeof(uint32_t)) {
        return 0;
    }

    uint32_t numerator = *(uint32_t*)(data);
    uint32_t denominator = *(uint32_t*)(data + sizeof(uint32_t));

    divide(numerator, denominator);
    return 0;
}

Using FuzzedDataProvider:

cpp
#include "FuzzedDataProvider.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    FuzzedDataProvider fuzzed_data(data, size);

    size_t allocation_size = fuzzed_data.ConsumeIntegral<size_t>();
    std::vector<char> str1 = fuzzed_data.ConsumeBytesWithTerminator<char>(32, 0xFF);
    std::vector<char> str2 = fuzzed_data.ConsumeBytesWithTerminator<char>(32, 0xFF);

    concat(&str1[0], str1.size(), &str2[0], str2.size(), allocation_size);
    return 0;
}
Step 5: Test and Iterate

Run the fuzzer and monitor:

  • Code coverage (are all interesting paths reached?)
  • Executions per second (is it fast enough?)
  • Crash reproducibility (can you reproduce crashes with saved inputs?)

Iterate on the harness to improve these metrics.

Common Patterns

Pattern: Beyond Byte Arrays—Casting to Integers

Use Case: When target expects primitive types like integers or floats

Implementation:

cpp
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Ensure exactly 2 4-byte numbers
    if (size != 2 * sizeof(uint32_t)) {
        return 0;
    }

    // Split input into two integers
    uint32_t numerator = *(uint32_t*)(data);
    uint32_t denominator = *(uint32_t*)(data + sizeof(uint32_t));

    divide(numerator, denominator);
    return 0;
}

Rust equivalent:

rust
fuzz_target!(|data: &[u8]| {
    if data.len() != 2 * std::mem::size_of::<i32>() {
        return;
    }

    let numerator = i32::from_ne_bytes([data[0], data[1], data[2], data[3]]);
    let denominator = i32::from_ne_bytes([data[4], data[5], data[6], data[7]]);

    divide(numerator, denominator);
});

Why it works: Any 8-byte input is valid. The fuzzer learns that inputs must be exactly 8 bytes, and every bit flip produces a new, potentially interesting input.

Pattern: FuzzedDataProvider for Complex Inputs

Use Case: When target requires multiple strings, integers, or variable-length data

Implementation:

cpp
#include "FuzzedDataProvider.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    FuzzedDataProvider fuzzed_data(data, size);

    // Extract different types of data
    size_t allocation_size = fuzzed_data.ConsumeIntegral<size_t>();

    // Consume variable-length strings with terminator
    std::vector<char> str1 = fuzzed_data.ConsumeBytesWithTerminator<char>(32, 0xFF);
    std::vector<char> str2 = fuzzed_data.ConsumeBytesWithTerminator<char>(32, 0xFF);

    char* result = concat(&str1[0], str1.size(), &str2[0], str2.size(), allocation_size);
    if (result != NULL) {
        free(result);
    }

    return 0;
}

Why it helps: FuzzedDataProvider handles the complexity of extracting structured data from a byte stream. It's particularly useful for APIs that need multiple parameters of different types.

Pattern: Interleaved Fuzzing

Use Case: When multiple related operations should be tested in a single harness

Implementation:

cpp
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    if (size < 1 + 2 * sizeof(int32_t)) {
        return 0;
    }

    // First byte selects operation
    uint8_t mode = data[0];

    // Next bytes are operands
    int32_t numbers[2];
    memcpy(numbers, data + 1, 2 * sizeof(int32_t));

    int32_t result = 0;
    switch (mode % 4) {
        case 0:
            result = add(numbers[0], numbers[1]);
            break;
        case 1:
            result = subtract(numbers[0], numbers[1]);
            break;
        case 2:
            result = multiply(numbers[0], numbers[1]);
            break;
        case 3:
            result = divide(numbers[0], numbers[1]);
            break;
    }

    // Prevent compiler from optimizing away the calls
    printf("%d", result);
    return 0;
}

Advantages:

  • Faster to write one harness than multiple individual harnesses
  • Single shared corpus means interesting inputs for one operation may be interesting for others
  • Can discover bugs in interactions between operations

When to use:

  • Operations share similar input types
  • Operations are logically related (e.g., arithmetic operations, CRUD operations)
  • Single corpus makes sense across all operations
Pattern: Structure-Aware Fuzzing with Arbitrary (Rust)

Use Case: When fuzzing Rust code that uses custom structs

Implementation:

rust
use arbitrary::Arbitrary;

#[derive(Debug, Arbitrary)]
pub struct Name {
    data: String
}

impl Name {
    pub fn check_buf(&self) {
        let data = self.data.as_bytes();
        if data.len() > 0 && data[0] == b'a' {
            if data.len() > 1 && data[1] == b'b' {
                if data.len() > 2 && data[2] == b'c' {
                    process::abort();
                }
            }
        }
    }
}

Harness with arbitrary:

rust
#![no_main]
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: your_project::Name| {
    data.check_buf();
});

Add to Cargo.toml:

toml
[dependencies]
arbitrary = { version = "1", features = ["derive"] }

Why it helps: The arbitrary crate automatically handles deserialization of raw bytes into your Rust structs, reducing boilerplate and ensuring valid struct construction.

Limitation: The arbitrary crate doesn't offer reverse serialization, so you can't manually construct byte arrays that map to specific structs. This works best when starting from an empty corpus (fine for libFuzzer, problematic for AFL++).

Advanced Usage

Tips and Tricks
TipWhy It Helps
Start with parsersHigh bug density, clear entry points, easy to harness
Mock I/O operationsPrevents hangs from blocking I/O, enables determinism
Use FuzzedDataProviderSimplifies extraction of structured data from raw bytes
Reset global stateEnsures each iteration is independent and reproducible
Free resources in harnessPrevents memory exhaustion during long campaigns
Avoid logging in harnessLogging is slow—fuzzing needs 100s-1000s exec/sec
Test harness manually firstRun harness with known inputs before starting campaign
Check coverage earlyEnsure harness reaches expected code paths
Structure-Aware Fuzzing with Protocol Buffers

For highly structured input formats, consider using Protocol Buffers as an intermediate format with custom mutators:

cpp
// Define your input format in .proto file
// Use libprotobuf-mutator to generate valid mutations
// This ensures fuzzer mutates message contents, not the protobuf encoding itself

This approach is more setup but prevents the fuzzer from wasting time on unparseable inputs. See structure-aware fuzzing documentation for details.

Handling Non-Determinism

Problem: Random values or timing dependencies cause non-reproducible crashes.

Solutions:

  • Replace rand() with deterministic PRNG seeded from fuzzer input:
    cpp
    uint32_t seed = fuzzed_data.ConsumeIntegral<uint32_t>();
    srand(seed);
  • Mock system calls that return time, PIDs, or random data
  • Avoid reading from /dev/random or /dev/urandom
Resetting Global State

If your SUT uses global state (singletons, static variables), reset it between iterations:

cpp
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Reset global state before each iteration
    global_reset();

    target_function(data, size);

    // Clean up resources
    global_cleanup();
    return 0;
}

Rationale: Global state can cause crashes after N iterations rather than on a specific input, making bugs non-reproducible.

Show full SKILL.md (750 more words)Show less

Practical Harness Rules

Follow these rules to ensure effective fuzzing harnesses:

RuleRationale
Handle all input sizesFuzzer generates empty, tiny, huge inputs—harness must handle gracefully
Never call exit()Calling exit() stops the fuzzer process. Use abort() in SUT if needed
Join all threadsEach iteration must run to completion before next iteration starts
Be fastAim for 100s-1000s executions/sec. Avoid logging, high complexity, excess memory
Maintain determinismSame input must always produce same behavior for reproducibility
Avoid global stateGlobal state reduces reproducibility—reset between iterations if unavoidable
Use narrow targetsDon't fuzz PNG and TCP in same harness—different formats need separate targets
Free resourcesPrevent memory leaks that cause resource exhaustion during long campaigns

Note: These guidelines apply not just to harness code, but to the entire SUT. If the SUT violates these rules, consider patching it (see the fuzzing obstacles technique).

Anti-Patterns

Anti-PatternProblemCorrect Approach
Global state without resetNon-deterministic crashesReset all globals at start of harness
Blocking I/O or network callsHangs fuzzer, wastes timeMock I/O, use in-memory buffers
Memory leaks in harnessResource exhaustion kills campaignFree all allocations before returning
Calling exit() in SUTStops entire fuzzing processUse abort() or return error codes
Heavy logging in harnessReduces exec/sec by orders of magnitudeDisable logging during fuzzing
Too many operations per iterationSlows down fuzzerKeep iterations fast and focused
Mixing unrelated input formatsCorpus entries not useful across formatsSeparate harnesses for different formats
Not validating input sizeHarness crashes on edge casesCheck size before accessing data

Tool-Specific Guidance

libFuzzer

Harness signature:

cpp
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Your code here
    return 0;  // Non-zero return is reserved for future use
}

Compilation:

bash
clang++ -fsanitize=fuzzer,address -g harness.cc -o fuzz_target

Integration tips:

  • Use FuzzedDataProvider.h for structured input extraction
  • Compile with -fsanitize=fuzzer to link the fuzzing runtime
  • Add sanitizers (-fsanitize=address,undefined) to detect more bugs
  • Use -g for better stack traces when crashes occur
  • libFuzzer can start with empty corpus—no seed inputs required

Running:

bash
./fuzz_target corpus_dir/

Resources:

AFL++

AFL++ supports multiple harness styles. For best performance, use persistent mode:

Persistent mode harness:

cpp
#include <unistd.h>

int main(int argc, char **argv) {
    #ifdef __AFL_HAVE_MANUAL_CONTROL
        __AFL_INIT();
    #endif

    unsigned char buf[MAX_SIZE];

    while (__AFL_LOOP(10000)) {
        // Read input from stdin
        ssize_t len = read(0, buf, sizeof(buf));
        if (len <= 0) break;

        // Call target function
        target_function(buf, len);
    }

    return 0;
}

Compilation:

bash
afl-clang-fast++ -g harness.cc -o fuzz_target

Integration tips:

  • Use persistent mode (__AFL_LOOP) for 10-100x speedup
  • Consider deferred initialization (__AFL_INIT()) to skip setup overhead
  • AFL++ requires at least one seed input in the corpus directory
  • Use AFL_USE_ASAN=1 or AFL_USE_UBSAN=1 for sanitizer builds

Running:

bash
afl-fuzz -i seeds/ -o findings/ -- ./fuzz_target
cargo-fuzz (Rust)

Harness signature:

rust
#![no_main]
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    // Your code here
});

With structured input (arbitrary crate):

rust
#![no_main]
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: YourStruct| {
    data.check();
});

Creating harness:

bash
cargo fuzz init
cargo fuzz add my_target

Integration tips:

  • Use arbitrary crate for automatic struct deserialization
  • cargo-fuzz wraps libFuzzer, so all libFuzzer features work
  • Compile with sanitizers automatically via cargo-fuzz
  • Harnesses go in fuzz/fuzz_targets/ directory

Running:

bash
cargo +nightly fuzz run my_target

Resources:

go-fuzz

Harness signature:

go
// +build gofuzz

package mypackage

func Fuzz(data []byte) int {
    // Call target function
    target(data)

    // Return codes:
    // -1 if input is invalid
    //  0 if input is valid but not interesting
    //  1 if input is interesting (e.g., added new coverage)
    return 0
}

Building:

bash
go-fuzz-build

Integration tips:

  • Return 1 for inputs that add coverage (optional—fuzzer can detect automatically)
  • Return -1 for invalid inputs to deprioritize similar mutations
  • go-fuzz handles persistence automatically

Running:

bash
go-fuzz -bin=./mypackage-fuzz.zip -workdir=fuzz

Troubleshooting

IssueCauseSolution
Low executions/secHarness is too slow (logging, I/O, complexity)Profile harness, remove bottlenecks, mock I/O
No crashes foundCoverage not reaching buggy codeCheck coverage, improve harness to reach more paths
Non-reproducible crashesNon-determinism or global stateRemove randomness, reset globals between iterations
Fuzzer exits immediatelyHarness calls exit()Replace exit() with abort() or return error
Out of memory errorsMemory leaks in harness or SUTFree allocations, use leak sanitizer to find leaks
Crashes on empty inputHarness doesn't validate sizeAdd if (size < MIN_SIZE) return 0;
Corpus not growingInputs too constrained or format too strictUse FuzzedDataProvider or structure-aware fuzzing
Tools That Use This Technique
SkillHow It Applies
libfuzzerUses LLVMFuzzerTestOneInput harness signature with FuzzedDataProvider
aflppSupports persistent mode harnesses with __AFL_LOOP for performance
cargo-fuzzUses Rust-specific fuzz_target! macro with arbitrary crate integration
atherisPython harness takes bytes, calls Python functions
ossfuzzRequires harnesses in specific directory structure for cloud fuzzing
SkillRelationship
coverage-analysisMeasure harness effectiveness—are you reaching target code?
address-sanitizerDetects bugs found by harness (buffer overflows, use-after-free)
fuzzing-dictionaryProvide tokens to help fuzzer pass format checks in harness
fuzzing-obstaclesPatch SUT when it violates harness rules (exit, non-determinism)

Resources

Key External Resources

Split Inputs in libFuzzer - Google Fuzzing Docs Explains techniques for handling multiple input parameters in a single fuzzing harness, including use of magic separators and FuzzedDataProvider.

Structure-Aware Fuzzing with Protocol Buffers Advanced technique using protobuf as intermediate format with custom mutators to ensure fuzzer mutates message contents rather than format encoding.

libFuzzer Documentation Official LLVM documentation covering harness requirements, best practices, and advanced features.

cargo-fuzz Book Comprehensive guide to writing Rust fuzzing harnesses with cargo-fuzz and the arbitrary crate.

Video Resources

© trailofbits, CC-BY-SA-4.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 2 other files (assets) in plugins/testing-handbook-skills/skills/harness-writing of trailofbits/skills.

  • SKILL.md
  • agents/openai.yaml
  • assets/trail-of-bits-mark.svg

Open the folder on GitHubat commit 82fe822

Used in 1 other repository

We found 1 copy of this SKILL.md (exact, near-identical or edited) in other folders, from 1 other GitHub owner. This page covers the copy in trailofbits/skills, which our catalogue first saw on October 7, 2026.

Compare with similar skills

Fuzzing Harness Design next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Fuzzing Harness Design compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Fuzzing Harness Design this skilltrailofbits/skills7.4k1 repos~5.3kAutomated safety check: PassCC-BY-SA-4.0
Audit Native Memory Safetycyberful/cyberful135—~829Automated safety check: PassAGPL-3.0
Harness Design Fuzzingprovos/ironcurtain613—~5.7kAutomated safety check: PassApache-2.0
ClusterfuzzliteInternationalColorConsortium/iccDEV183—~1.5kAutomated safety check: PassBSD-3-Clause
Fuzzingnwjs/chromium.src160—~1.1kAutomated safety check: PassBSD-3-Clause
Fuzzingmohitmishra786/low-level-dev-skills253—~2.1kAutomated safety check: PassMIT

Similar skills

  • Audit C, C++, unsafe Rust, native extensions, parsers, codecs, FFI boundaries, and systems code for memory corruption and low-level exploitation risk.

    135 GitHub stars~829 tokensUpdated 1 mo ago
    SecurityAuto-check passed
  • Harness Design Fuzzing

    provos/ironcurtain

    Reference vocabulary for designing instrumented harnesses that drive vulnerability discovery — design classes (trigger-driven vs coverage-driven), tiered scope (T1 isolated function / T2…

    613 GitHub stars~5.7k tokensUpdated yesterday
    SecurityAuto-check passed
  • Clusterfuzzlite

    InternationalColorConsortium/iccDEV

    Build, test, or update the iccDEV ClusterFuzzLite libFuzzer integration across ASan, UBSan, and MSan.

    183 GitHub stars~1.5k tokensUpdated today
    SecurityAuto-check passed
  • Fuzzing

    nwjs/chromium.src

    Implements, registers, and verifies fuzz tests in Chromium. An agent skill from nwjs/chromium.src.

    160 GitHub stars~1.1k tokensUpdated 4 days ago
    SecurityAuto-check passed
  • Fuzzing

    mohitmishra786/low-level-dev-skills

    Fuzzing skill for automated input-driven bug finding in C/C++.

    253 GitHub stars~2.1k tokensUpdated 3 mo ago
    SecurityAuto-check passed
  • Rust Security

    mohitmishra786/low-level-dev-skills

    Rust security skill for supply chain safety and memory-safe development.

    253 GitHub stars~1.6k tokensUpdated 3 mo ago
    SecurityAuto-check passed

More from trailofbits/skills

All 79 skills in this repo
  • Code Graph Mermaid Diagrams

    trailofbits/skills

    Official

    Generates Mermaid diagrams from Trailmark code graphs, including call graphs, class hierarchies, module dependency maps, complexity heatmaps and attack surface data flows.

    7.4k GitHub starsUsed in 1 repo~1.7k tokens
    Auto-check passed
  • CodeQL Security Scan

    trailofbits/skills

    Official

    Scans a codebase for vulnerabilities with CodeQL's data flow and taint tracking in run-all or important-only modes, including data extensions for project-specific sources and sinks.

    7.4k GitHub stars~4.6k tokensUpdated yesterday
    Auto-check: notes
  • Trailmark Graph Evolution

    trailofbits/skills

    Official

    Compares Trailmark code graphs at two snapshots, such as commits, tags or directories, to surface attack paths, blast radius and taint changes that text diffs miss.

    7.4k GitHub stars~3.4k tokensUpdated yesterday
    Auto-check passed
  • Let Fate Decide

    trailofbits/skills

    Official

    Draws a 12 Houses tarot spread to break ties when a request is vague or casually delegated, then reads the cards to pick the next step.

    7.4k GitHub stars~2.5k tokensUpdated yesterday
    Auto-check: notes
  • Burp Suite Project Parser

    trailofbits/skills

    Official

    Searches and extracts data from Burp Suite project files on the command line: regex searches over responses, audit findings, proxy history and site map data.

    7.4k GitHub starsUsed in 4 repos~4.2k tokens
    Auto-check: notes
  • Semgrep Security Scan

    trailofbits/skills

    Official

    Detects languages, proposes rulesets for approval, then runs the approved Semgrep scan across a codebase and merges the output into one SARIF file.

    7.4k GitHub stars~3.7k tokensUpdated yesterday
    Auto-check: notes

Works with

Questions about Fuzzing Harness Design

What does Fuzzing Harness Design do?

Guides writing and improving fuzzing harnesses for C, C++ and Rust so random byte input gets translated into structured, reproducible test cases for the target code. This skill treats the harness, the entry point that receives fuzzer bytes and calls the system under test, as the single biggest factor in whether a fuzzing campaign finds real bugs., FuzzedDataProvider for turning raw bytes into typed values, determinism, and interleaved fuzzing where one harness exercises several operations based on its input.

When should I use Fuzzing Harness Design?

Fuzzing Harness Design fits situations like: writing a first fuzz harness for a C, C++ or Rust library; fixing a fuzzing campaign that finds no bugs or has low coverage; debugging a fuzzer crash that will not reproduce; deciding whether to fuzz several related functions together with one harness.

How do I install Fuzzing Harness Design in Claude Code?

Run `npx skills add trailofbits/skills --skill harness-writing -a claude-code`. Or copy the skill folder (plugins/testing-handbook-skills/skills/harness-writing in trailofbits/skills) into .claude/skills/harness-writing in your project. Claude Code loads it when a task matches its description.

How do I install Fuzzing Harness Design in Codex?

Run `npx skills add trailofbits/skills --skill harness-writing -a codex`. Or copy the skill folder (plugins/testing-handbook-skills/skills/harness-writing in trailofbits/skills) into .agents/skills/harness-writing in your project. Codex loads it when a task matches its description.

Can I use Fuzzing Harness Design in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add trailofbits/skills --skill harness-writing -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/harness-writing, .gemini/skills/harness-writing, .github/skills/harness-writing and .opencode/skills/harness-writing in your project.

What does Fuzzing Harness Design need to run?

Going by SKILL.md and its folder, Fuzzing Harness Design needs the command-line tools its instructions call (cargo). Our summary lists: A C, C++ or Rust codebase with a fuzzing toolchain such as libFuzzer or cargo-fuzz.

Does Fuzzing Harness Design access the network?

SKILL.md names 4 domains. As links in the text: github.com, llvm.org, rust-fuzz.github.io and youtube.com. This is read from the text; nothing was executed.

Is Fuzzing Harness Design safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Fuzzing Harness Design use?

Fuzzing Harness Design is published under the CC-BY-SA-4.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Fuzzing Harness Design use?

About 5.3k tokens (SKILL.md is roughly 21k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Fuzzing Harness Design?

Skills that share tags, products or a category with Fuzzing Harness Design: Audit Native Memory Safety (cyberful/cyberful, 135 stars), Harness Design Fuzzing (provos/ironcurtain, 613 stars), Clusterfuzzlite (InternationalColorConsortium/iccDEV, 183 stars) and Fuzzing (nwjs/chromium.src, 160 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Fuzzing Harness Design?

trailofbits (a GitHub organization, an official publisher) maintains it in trailofbits/skills, which has 7,420 GitHub stars. The repository holds 79 skills in this directory. The repository was last updated on October 7, 2026.

Source: trailofbits/skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.