fuzzing — Claude Code skill: what it does, how to install
Guides agents in writing fuzz targets for C and C++, configuring libFuzzer or AFL++, and wiring coverage-guided tests into CI pipelines.
npx skills add mohitmishra786/low-level-dev-skills --skill fuzzing -a claude-codeWhat fuzzing does
The skill instructs coding agents on setting up coverage-guided fuzz testing for C and C++ codebases. It covers in-process testing with libFuzzer, compilation flags in Clang, and sanitizer support such as AddressSanitizer.
It includes templates for persistent mode in AFL++ using __AFL_LOOP and corpus minimization with afl-cmin. It also outlines custom mutators via LLVMFuzzerCustomMutator alongside Python testing with Atheris.
Flags like -fsanitize=fuzzer provide a built-in main(), so declaring a manual main in the harness breaks the build. Crash artifacts from crash-* files can be passed directly into GDB.
What it helps with
- Write a
LLVMFuzzerTestOneInputharness for C and C++ parsers - Compile targets using Clang with AddressSanitizer and UBSan flags
- Run AFL++ persistent mode to avoid per-run
fork()overhead - Minimize fuzzing corpus directories before running CI regression checks
Example prompts for the agent
- Help me write a libFuzzer target for my C parser
- How do I build this library with AFL++ persistent mode?
- Set up a short 60-second libFuzzer regression step in GitHub Actions
How to install fuzzing
1Skills CLI (Vercel)
npx skills add mohitmishra786/low-level-dev-skills --skill fuzzing -a claude-code2Manually: put the files in place
~/.claude/skills/fuzzing/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/fuzzing/
1Skills CLI (Vercel)
npx skills add mohitmishra786/low-level-dev-skills --skill fuzzing -a codex2Manually: put the files in place
.agents/skills/fuzzing/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add mohitmishra786/low-level-dev-skills --skill fuzzing -a cursor2Manually: put the files in place
.cursor/skills/fuzzing/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install mohitmishra786/low-level-dev-skills fuzzing2Manually: put the files in place
.github/skills/fuzzing/SKILL.md1Skills CLI (Vercel)
npx skills add mohitmishra786/low-level-dev-skills --skill fuzzing -a gemini-cli2Platform CLI
gemini skills install https://github.com/mohitmishra786/low-level-dev-skills --path skills/runtimes/fuzzingManually: put the files in place
.devin/skills/fuzzing/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add mohitmishra786/low-level-dev-skills --skill fuzzing -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about fuzzing
How to install fuzzing in Claude Code?
Run npx skills add mohitmishra786/low-level-dev-skills --skill fuzzing -a claude-code. The file will be placed at ~/.claude/skills/fuzzing/SKILL.md.
What does the fuzzing skill do?
It guides AI agents through writing target harnesses, configuring Clang sanitizers, launching libFuzzer or AFL++, and minimizing corpora.
Why use persistent mode in AFL++?
Running persistent mode with __AFL_LOOP eliminates fork() overhead on every iteration. It speeds up library fuzz testing significantly.
Source text
SKILL.md · MIT
---
name: fuzzing
description: Fuzzing skill for automated input-driven bug finding in C/C++. Use when setting up libFuzzer or AFL++ fuzz targets, defining fuzz entry points around parsing or I/O boundaries, integrating fuzzing into CI, managing corpora, or combining fuzzing with sanitizers. Activates on queries about libFuzzer, AFL, afl-fuzz, fuzz targets, corpus management, coverage-guided fuzzing, or OSS-Fuzz integration.
---
# Fuzzing
## Purpose
Guide agents through setting up and running coverage-guided fuzz testing: libFuzzer (in-process) and AFL++ (fork-based), with sanitizer integration and CI pipeline setup.
## Triggers
- "How do I fuzz-test my parser/deserializer?"
- "What is a fuzz target / how do I write one?"
- "How do I set up libFuzzer?"
- "How do I use AFL++ on my program?"
- "How do I run fuzzing in CI?"
- "Fuzzer found a crash — how do I reproduce it?"
## Workflow
### 1. Write a fuzz target (libFuzzer)
A fuzz target is a function that accepts arbitrary bytes and exercises the code under test.
```c
// fuzz_parser.c
#include <stdint.h>
#include <stddef.h>
#include "myparser.h"
// Entry point called by libFuzzer with random data
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// Must not abort/exit on invalid input (that's expected)
// Must not read outside [data, data+size)
MyParser *p = parser_create();
if (p) {
parser_feed(p, (const char *)data, size);
parser_destroy(p);
}
return 0; // Always return 0 (non-zero means discard input)
}
```
Key rules:
- Never call `abort()`, `exit()`, or use global state that persists across calls
- Handle all inputs gracefully (crash = bug found)
- Keep the target fast: the fuzzer calls it millions of times
### 2. Build with libFuzzer
```bash
# Clang (libFuzzer is built into Clang)
clang -fsanitize=fuzzer,address -g -O1 \
fuzz_parser.c myparser.c -o fuzz_parser
# With UBSan too
clang -fsanitize=fuzzer,address,undefined -g -O1 \
fuzz_parser.c myparser.c -o fuzz_parser
```
`-fsanitize=fuzzer` links libFuzzer and provides `main()`. Do not provide your own `main()` in the fuzz target.
### 3. Run libFuzzer
```bash
# Create corpus directory
mkdir -p corpus
# Seed with known-good inputs (greatly accelerates coverage)
cp tests/inputs/* corpus/
# Run the fuzzer
./fuzz_parser corpus/ -max_len=65536 -timeout=10
# Run for a time limit
./fuzz_parser corpus/ -max_total_time=3600
# Run with specific number of jobs (parallel)
./fuzz_parser corpus/ -jobs=4 -workers=4
# Minimise a corpus (remove redundant inputs)
./fuzz_parser -merge=1 corpus_min/ corpus/
```
Common flags:
| Flag | Default | Effect |
|------|---------|--------|
| `-max_len=N` | 4096 | Max input size in bytes |
| `-timeout=N` | 1200 | Kill if single run takes > N seconds |
| `-max_total_time=N` | 0 (forever) | Total fuzzing time |
| `-runs=N` | -1 (infinite) | Total number of runs |
| `-dict=file` | none | Dictionary of interesting tokens |
| `-jobs=N` | 1 | Parallel jobs (each writes its own log) |
| `-merge=1` | off | Merge mode: minimise corpus |
### 4. Reproduce a crash
libFuzzer writes crash inputs to files named `crash-<hash>`, `oom-<hash>`, `timeout-<hash>`.
```bash
# Reproduce
./fuzz_parser crash-abc123
# Debug with GDB
gdb ./fuzz_parser
(gdb) run crash-abc123
```
### 5. AFL++ setup
AFL++ is a fork-based fuzzer that works on arbitrary programs (not just those with a fuzz entry point).
```bash
# Install
apt install afl++ # or build from source
# Instrument the target
CC=afl-clang-fast CXX=afl-clang-fast++ \
cmake -S . -B build-afl -DCMAKE_BUILD_TYPE=Debug
cmake --build build-afl
# Or compile directly
afl-clang-fast -g -O1 -o prog_afl main.c myparser.c
# Create input corpus
mkdir -p afl-input afl-output
echo "hello" > afl-input/seed1
# Run
afl-fuzz -i afl-input -o afl-output -- ./prog_afl @@
# @@ is replaced with the input file path
# For stdin-based programs: remove @@
afl-fuzz -i afl-input -o afl-output -- ./prog_afl
```
### 6. AFL++ with persistent mode (faster)
Persistent mode avoids `fork()` per input — much faster for library fuzzing:
```c
// In your harness:
#include "myparser.h"
int main(int argc, char **argv) {
while (__AFL_LOOP(1000)) {
// Read input
unsigned char *buf = NULL;
ssize_t len = read(0, &buf, MAX_SIZE); // or use afl_custom_mutator
parser_feed((char*)buf, len);
free(buf);
}
return 0;
}
```
### 7. Corpus management
```bash
# AFL++ corpus minimisation
afl-cmin -i afl-output/default/queue -o corpus_min -- ./prog_afl @@
# Merge libFuzzer corpora from multiple runs
./fuzz_parser -merge=1 merged_corpus/ run1_corpus/ run2_corpus/
# Show coverage (libFuzzer)
./fuzz_parser corpus/ -runs=0 -print_coverage=1
```
### 8. CI integration
```yaml
# GitHub Actions example
- name: Build fuzz targets
run: |
clang -fsanitize=fuzzer,address,undefined -g -O1 \
fuzz_parser.c myparser.c -o fuzz_parser
- name: Short fuzz run (regression check)
run: |
./fuzz_parser corpus/ -max_total_time=60 -error_exitcode=1
# Also run known crash inputs if any:
ls known_crashes/ 2>/dev/null | xargs -I{} ./fuzz_parser known_crashes/{}
```
For long-duration fuzzing, use OSS-Fuzz or ClusterFuzz infrastructure.
### 9. Structure-aware fuzzing (libFuzzer)
```c
// Custom mutator hook — preserve format invariants
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed) {
// Delegate to default mutator then fix up structure
Size = LLVMFuzzerMutate(Data, Size, MaxSize);
if (Size >= 4)
fix_checksum(Data, Size);
return Size;
}
// Register custom crossover for structured inputs
extern "C" size_t LLVMFuzzerCustomCrossOver(
const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize, unsigned int Seed);
```
Use when naive bit-flipping breaks checksums/headers before reaching deep code paths.
### 10. Atheris (Python fuzzing)
```python
import atheris
import sys
with atheris.instrument_imports():
import myparser
def TestOneInput(data: bytes) -> None:
fdp = atheris.FuzzedDataProvider(data)
try:
myparser.parse(fdp.ConsumeString(sys.maxsize))
except myparser.ParseError:
pass
if __name__ == "__main__":
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()
```
```bash
pip install atheris
python fuzz_myparser.py corpus/ -max_total_time=300
```
### 11. Dataflow tracing
```bash
# Track tainted bytes through execution (LLVM dataflow sanitizer + libFuzzer)
clang -fsanitize=fuzzer,dataflow -g -O1 fuzz.c target.c -o fuzz
LIBFUZZER_DATAFLOW_TRACE=1 ./fuzz corpus/
```
Produces traces showing which input bytes influenced branches — guides dictionary and structure-aware mutators.
### 12. OSS-Fuzz integration
```
OSS-Fuzz workflow
├── Add project/ in google/oss-fuzz repo (Dockerfile + build.sh)
├── Fuzz targets linked with -fsanitize=fuzzer,address
├── ClusterFuzz runs continuously on GCE
└── Crash reproducers uploaded to issue tracker
```
```dockerfile
# project/Dockerfile (minimal)
FROM gcr.io/oss-fuzz-base/base-builder
RUN git clone --depth 1 https://github.com/you/yourproject
WORKDIR yourproject
COPY build.sh $SRC/
```
```bash
# Local OSS-Fuzz repro
python infra/helper.py build_image yourproject
python infra/helper.py build_fuzzers yourproject
python infra/helper.py run_fuzzer yourproject fuzz_target
```
### 13. Zig fuzz testing
```bash
# Zig 0.11+ built-in fuzzing
zig build test --fuzz
# fuzz target in build.zig
# .root_module.fuzz_tests = &.{
# .{ .name = "parser", .path = "src/fuzz/parser.zig" },
# };
```
Zig fuzz integrates with `zig test` and sanitizer builds for native targets.
### 14. Dictionary files
Dictionaries contain interesting tokens to guide mutation:
```bash
# parser.dict
kw1="<"
kw2=">"
kw3="</"
kw4='="'
kw5="\x00"
kw6="\xff\xfe"
```
```bash
./fuzz_parser corpus/ -dict=parser.dict
```
## References
For fuzz target templates, corpus seed examples, and OSS-Fuzz integration guidance, see [references/targets.md](references/targets.md).
## Related skills
- Use `skills/runtimes/sanitizers` to add ASan/UBSan to fuzz builds
- Use `skills/compilers/clang` for Clang-specific libFuzzer flags
- Use `skills/debuggers/gdb` to debug crash inputs found by the fuzzer
- Use `skills/zig/zig-testing` for Zig `build test --fuzz` workflows
- Use `skills/security/kernel-security` for kernel fuzzing with syzkaller
© mohitmishra786 · MIT · mohitmishra786/low-level-dev-skills