implementing-fuzz-testing-in-cicd-with-aflplusplus skill (Anthropic-Cybersecurity-Skills)
- Install
- SKILL.md (verbatim)
- Overview
- When to Use
- Prerequisites
- Core Concepts
- Coverage-Guided Fuzzing
- Instrumentation Modes
- Persistent Mode
- Workflow
- Step 1 --- Build the Fuzzing Harness
- Step 2 --- Compile with AFL++ Instrumentation
- Step 3 --- Prepare Seed Corpus
- Step 4 --- Configure CI/CD Integration
- Step 5 --- Parallel Fuzzing for Nightly Runs
- Step 6 --- Crash Triage
- CI/CD Best Practices for AFL++
- Monitoring Fuzzing Campaigns
- References
- Other files in this skill
- assets/template.md (verbatim)
- Target Application
- Fuzzing Configuration
- Corpus Management
- Crash Tracking
- references/api-reference.md (verbatim)
- Libraries Used
- CLI Interface
- Core Functions
- compiletarget(sourcefile, outputbinary, compiler)
- runfuzzer(binary, inputdir, outputdir, durationseconds, memorylimit)
- parsefuzzerstats(statsfile)
- triagecrashes(binary, crashesdir)
- minimizecorpus(binary, inputdir, outputdir, timeout)
- AFL++ Commands Used
- Dependencies
- references/standards.md (verbatim)
- NIST SP 800-53 Rev 5 Controls
- OWASP Testing Guide v4.2
- CWE Categories Commonly Found by Fuzzing
- Fuzzing Maturity Levels
- references/workflows.md (verbatim)
- Workflow 1: CI Pipeline Integration
- Workflow 2: Nightly Fuzzing Campaign
- Workflow 3: Crash Triage and Fix
What it does. Integrates AFL++ coverage-guided fuzzing into CI/CD pipelines, covering harness construction, AFL++/AddressSanitizer/CmpLog instrumentation builds, and persistent-mode fuzzing to discover memory-corruption and input-handling vulnerabilities in C/C++ code. Use when adding automated fuzz testing to a build pipeline or hunting for memory-safety bugs in native/compiled applications. Part of mukul975/Anthropic-Cybersecurity-Skills (817 security skills) (mukul975/Anthropic-Cybersecurity-Skills).
| Upstream | mukul975/Anthropic-Cybersecurity-Skills |
| Skill file | skills/implementing-fuzz-testing-in-cicd-with-aflplusplus/SKILL.md |
| License | Apache-2.0 (skill folder LICENSE) |
| Author | mukul975 |
| Fetched | 2026-09-10 |
Install
npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill implementing-fuzz-testing-in-cicd-with-aflplusplus, or copy the skill folder into~/.claude/skills/implementing-fuzz-testing-in-cicd-with-aflplusplus/.- Raw file:
curl -sL https://raw.githubusercontent.com/mukul975/Anthropic-Cybersecurity-Skills/HEAD/skills/implementing-fuzz-testing-in-cicd-with-aflplusplus/SKILL.md
SKILL.md (verbatim)
name: implementing-fuzz-testing-in-cicd-with-aflplusplus
description: Integrates AFL++ coverage-guided fuzzing into CI/CD pipelines, covering harness construction, AFL++/AddressSanitizer/CmpLog instrumentation builds, and persistent-mode fuzzing to discover memory-corruption and input-handling vulnerabilities in C/C++ code. Use when adding automated fuzz testing to a build pipeline or hunting for memory-safety bugs in native/compiled applications.
domain: cybersecurity
subdomain: devsecops
tags:
- aflplusplus
- fuzz-testing
- cicd
- coverage-guided-fuzzing
- security-testing
- vulnerability-discovery
- afl
version: '1.0'
author: mahipal
license: Apache-2.0
nist_ai_rmf:
- MEASURE-2.7
- MAP-5.1
- MANAGE-2.4
atlas_techniques:
- AML.T0070
- AML.T0066
- AML.T0082
nist_csf:
- PR.PS-01
- GV.SC-07
- ID.IM-04
- PR.PS-04
mitre_attack:
- T1195
- T1554
- T1059.004
- T1005
- T1059
Implementing Fuzz Testing in CI/CD with AFL++
Overview
AFL++ (American Fuzzy Lop Plus Plus) is a community-maintained fork of AFL that provides state-of-the-art coverage-guided fuzz testing for discovering vulnerabilities in compiled applications. AFL++ uses genetic algorithms to mutate inputs, tracking code coverage to find new execution paths that trigger crashes, hangs, and undefined behavior. In CI/CD environments, AFL++ can be integrated to continuously test parsers, protocol handlers, file format processors, and any code that handles untrusted input. AFL++ supports persistent mode for high-speed fuzzing (up to 100,000+ executions per second), custom mutators, QEMU mode for binary-only fuzzing, and CmpLog/RedQueen for automatic dictionary extraction.
When to Use
- When deploying or configuring implementing fuzz testing in cicd with aflplusplus capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
Prerequisites
- Linux-based CI runners (AFL++ does not support Windows natively)
- GCC or Clang compiler toolchain
- AFL++ installed (
apt install aflplusplusor built from source) - Target application with harness functions isolating input processing
- Seed corpus of valid input samples
Core Concepts
Coverage-Guided Fuzzing
AFL++ instruments the target binary at compile time (or via QEMU/Frida for binary-only targets) to track which code paths each input exercises. When a mutated input triggers a new code path, it is saved to the corpus for further mutation. This feedback loop enables AFL++ to systematically explore program state space.
Instrumentation Modes
| Mode | Use Case | Performance |
|---|---|---|
afl-clang-fast (LTO) |
Source available, best performance | Highest |
afl-clang-fast |
Source available, standard | High |
afl-gcc-fast |
GCC-based projects | High |
QEMU mode |
Binary-only, no source | Medium |
Frida mode |
Binary-only, cross-platform | Medium |
Unicorn mode |
Firmware, embedded | Low |
Persistent Mode
Persistent mode avoids fork overhead by fuzzing within a loop:
#include <unistd.h>
__AFL_FUZZ_INIT();
int main() {
__AFL_INIT();
unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
while (__AFL_LOOP(10000)) {
int len = __AFL_FUZZ_TESTCASE_LEN;
// Process buf[0..len-1]
parse_input(buf, len);
}
return 0;
}
Workflow
Step 1 --- Build the Fuzzing Harness
Create a harness that feeds AFL++ input to the target function:
// fuzz_harness.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "target_parser.h"
__AFL_FUZZ_INIT();
int main() {
__AFL_INIT();
unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
while (__AFL_LOOP(10000)) {
int len = __AFL_FUZZ_TESTCASE_LEN;
if (len < 4) continue;
// Reset state between iterations
parser_context_t ctx;
parser_init(&ctx);
parser_process(&ctx, buf, len);
parser_cleanup(&ctx);
}
return 0;
}
Step 2 --- Compile with AFL++ Instrumentation
# Standard instrumentation
export CC=afl-clang-fast
export CXX=afl-clang-fast++
# Enable AddressSanitizer for better crash detection
export AFL_USE_ASAN=1
# Build the target with instrumentation
$CC -o fuzz_harness fuzz_harness.c -ltarget_parser -fsanitize=address
# Build a CmpLog binary for better coverage
$CC -o fuzz_harness_cmplog fuzz_harness.c -ltarget_parser \
-fsanitize=address -DCMPLOG
Step 3 --- Prepare Seed Corpus
mkdir -p corpus/
# Add valid input samples
cp test_inputs/* corpus/
# Minimize the corpus
afl-cmin -i corpus/ -o corpus_min/ -- ./fuzz_harness @@
# Further minimize individual inputs
mkdir -p corpus_tmin/
for f in corpus_min/*; do
afl-tmin -i "$f" -o "corpus_tmin/$(basename $f)" -- ./fuzz_harness @@
done
Step 4 --- Configure CI/CD Integration
GitHub Actions:
name: Fuzz Testing
on:
push:
branches: [main]
schedule:
- cron: '0 2 * * *' # Nightly fuzzing
jobs:
fuzz:
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- name: Install AFL++
run: |
sudo apt-get update
sudo apt-get install -y aflplusplus
- name: Restore corpus cache
uses: actions/cache@v4
with:
path: corpus/
key: fuzz-corpus-${{ github.sha }}
restore-keys: fuzz-corpus-
- name: Build fuzzing harness
run: |
export CC=afl-clang-fast
export AFL_USE_ASAN=1
make fuzz_harness
- name: Run AFL++ fuzzing (CI mode)
env:
AFL_CMPLOG_ONLY_NEW: 1
AFL_FAST_CAL: 1
AFL_NO_STARTUP_CALIBRATION: 1
run: |
mkdir -p findings/
timeout 7200 afl-fuzz \
-S ci_fuzzer \
-i corpus/ \
-o findings/ \
-t 5000 \
-- ./fuzz_harness @@ || true
- name: Check for crashes
run: |
CRASHES=$(find findings/ -path "*/crashes/*" -not -name "README.txt" | wc -l)
echo "Found $CRASHES unique crashes"
if [ "$CRASHES" -gt 0 ]; then
echo "::error::AFL++ found $CRASHES crashes"
for crash in findings/*/crashes/*; do
[ -f "$crash" ] && echo "Crash: $crash ($(wc -c < $crash) bytes)"
done
exit 1
fi
- name: Update corpus cache
if: always()
run: |
afl-cmin -i findings/ci_fuzzer/queue/ -o corpus/ -- ./fuzz_harness @@
Step 5 --- Parallel Fuzzing for Nightly Runs
# Launch multiple secondary instances for better coverage
for i in $(seq 1 $(nproc)); do
afl-fuzz -S fuzzer_$i \
-i corpus/ \
-o findings/ \
-- ./fuzz_harness @@ &
done
# Wait for all fuzzers
wait
# Merge and minimize corpus
afl-cmin -i findings/*/queue/ -o corpus_merged/ -- ./fuzz_harness @@
Step 6 --- Crash Triage
# Reproduce and categorize crashes
for crash in findings/*/crashes/*; do
echo "=== Testing: $crash ==="
timeout 5 ./fuzz_harness_asan "$crash" 2>&1 | head -20
echo "---"
done
# Deduplicate crashes by stack trace
afl-collect findings/ crashes_deduped/ -- ./fuzz_harness @@
CI/CD Best Practices for AFL++
| Setting | CI Short Run | Nightly Long Run |
|---|---|---|
| Duration | 30-60 min | 4-24 hours |
| Mode | -S (secondary only) |
-S (no -M for CI) |
AFL_CMPLOG_ONLY_NEW |
1 | 1 |
AFL_FAST_CAL |
1 | 0 |
AFL_NO_STARTUP_CALIBRATION |
1 | 0 |
| Corpus caching | Required | Required |
| Parallel instances | 1-2 | nproc |
Monitoring Fuzzing Campaigns
# View fuzzing statistics
afl-whatsup findings/
# Key metrics to track:
# - Total paths found (code coverage indicator)
# - Unique crashes / unique hangs
# - Stability percentage (should be >90%)
# - Exec speed (execs/sec)
# - Cycles done (full corpus cycles completed)
References
- AFL++ Documentation
- AFL++ GitHub Repository
- AFL++ Fuzzing in Depth Guide
- Google Testing Handbook - AFL++
- OWASP Fuzzing Guide
Other files in this skill
- LICENSE
- assets/template.md
- references/api-reference.md
- references/standards.md
- references/workflows.md
- scripts/agent.py
- scripts/process.py
assets/template.md (verbatim)
Fuzz Testing Implementation Template
Target Application
| Field | Value |
|---|---|
| Application Name | |
| Target Function | |
| Language | [ ] C [ ] C++ [ ] Other |
| Input Type | [ ] File [ ] Network [ ] Stdin |
Fuzzing Configuration
| Parameter | Value |
|---|---|
| Instrumentation | [ ] afl-clang-fast [ ] afl-gcc-fast [ ] QEMU |
| Sanitizer | [ ] ASan [ ] UBSan [ ] MSan [ ] TSan |
| Mode | [ ] Persistent [ ] Fork |
| CmpLog | [ ] Enabled [ ] Disabled |
| Timeout per exec | ms |
| CI run duration | minutes |
| Nightly duration | hours |
Corpus Management
| Item | Location |
|---|---|
| Seed corpus | |
| Minimized corpus | |
| CI cache key |
Crash Tracking
| Crash ID | CWE | Severity | Crash File | Stack Trace Summary | Fix Status |
|---|---|---|---|---|---|
references/api-reference.md (verbatim)
API Reference — Implementing Fuzz Testing in CI/CD with AFL++
Libraries Used
- subprocess: Execute AFL++ toolchain commands (afl-clang-fast, afl-fuzz, afl-cmin)
- pathlib: File system operations for corpus and crash management
CLI Interface
python agent.py compile --source target.c --output target_fuzz [--compiler afl-clang-fast]
python agent.py fuzz --binary ./target_fuzz --input seeds/ --output findings/ [--duration 300]
python agent.py triage --binary ./target_fuzz --crashes-dir findings/default/crashes/
python agent.py stats --stats-file findings/default/fuzzer_stats
Core Functions
compile_target(source_file, output_binary, compiler)
Compiles target with AFL++ instrumentation. Sets AFL_HARDEN=1 for memory sanitizers.
run_fuzzer(binary, input_dir, output_dir, duration_seconds, memory_limit)
Runs afl-fuzz with headless mode (AFL_NO_UI=1), time-limited (-V flag).
Environment Variables Set:
| Variable | Value | Purpose |
|---|---|---|
AFL_SKIP_CPUFREQ |
1 | Skip CPU frequency check (CI/CD) |
AFL_NO_UI |
1 | Headless mode for CI environments |
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES |
1 | Continue on crash dir issues |
parse_fuzzer_stats(stats_file)
Parses AFL++ fuzzer_stats file. Key metrics: execs_per_sec, paths_total, saved_crashes, bitmap_cvg.
triage_crashes(binary, crashes_dir)
Re-runs crash inputs through the binary and classifies by signal (SIGSEGV, SIGABRT, etc.).
minimize_corpus(binary, input_dir, output_dir, timeout)
Runs afl-cmin to remove redundant seeds from the corpus.
AFL++ Commands Used
| Command | Purpose |
|---|---|
afl-clang-fast |
Compile with LLVM-based instrumentation |
afl-fuzz -i <in> -o <out> -- <binary> |
Main fuzzing loop |
afl-cmin -i <in> -o <out> -- <binary> |
Corpus minimization |
afl-tmin -i <crash> -o <min> -- <binary> |
Test case minimization |
Dependencies
AFL++ must be installed: apt install aflplusplus or build from source.
pip install # No Python packages needed beyond stdlib
references/standards.md (verbatim)
Standards Reference for Fuzz Testing
NIST SP 800-53 Rev 5 Controls
| Control | Description | Fuzzing Alignment |
|---|---|---|
| SA-11(5) | Penetration Testing | Fuzz testing discovers vulnerabilities through automated input mutation |
| SA-11(8) | Dynamic Code Analysis | AFL++ provides runtime analysis with instrumented binaries |
| SI-10 | Information Input Validation | Fuzzing validates input handling robustness |
| SI-17 | Fail-Safe Procedures | Crash detection ensures failures are handled safely |
OWASP Testing Guide v4.2
- WSTG-INPV-07: Testing for Input Validation --- AFL++ systematically tests boundary conditions
- WSTG-ERRH-01: Error Handling --- Crash analysis reveals improper error handling
CWE Categories Commonly Found by Fuzzing
| CWE | Name | AFL++ Detection Method |
|---|---|---|
| CWE-120 | Buffer Overflow | ASan crash on out-of-bounds write |
| CWE-125 | Out-of-Bounds Read | ASan crash on invalid read |
| CWE-416 | Use After Free | ASan detects freed memory access |
| CWE-476 | NULL Pointer Dereference | SIGSEGV on null deref |
| CWE-190 | Integer Overflow | UBSan detects arithmetic overflow |
| CWE-787 | Out-of-Bounds Write | ASan detects heap/stack buffer overflow |
| CWE-400 | Uncontrolled Resource Consumption | Timeout detection for hangs |
Fuzzing Maturity Levels
| Level | Description | CI Integration |
|---|---|---|
| 1 Basic | Manual ad-hoc fuzzing | None |
| 2 Structured | Harness-based with corpus management | PR-triggered short runs |
| 3 Continuous | Nightly campaigns with crash tracking | Nightly + corpus caching |
| 4 Optimized | Multi-tool (AFL++, libFuzzer), crash dedup, coverage tracking | Full CI/CD integration with gating |
references/workflows.md (verbatim)
AFL++ Fuzz Testing Workflows
Workflow 1: CI Pipeline Integration
Code pushed to branch
|
Fuzzing harness compiled with afl-clang-fast + ASan
|
Corpus restored from CI cache
|
AFL++ runs in secondary mode for fixed duration
|
[No crashes] --> Corpus updated in cache, pipeline passes
[Crashes found] --> Pipeline fails, crash artifacts uploaded
|
Developer triages crashes
|
Fix applied, re-run confirms no regression
Workflow 2: Nightly Fuzzing Campaign
Scheduled nightly trigger (cron)
|
Build instrumented binary + CmpLog binary
|
Restore merged corpus from last run
|
Launch parallel AFL++ instances (nproc count)
|
Run for 4-8 hours
|
Collect results from all instances
|
afl-cmin merges and minimizes corpus
|
Deduplicate crashes by stack hash
|
New crashes create Jira/GitHub issues automatically
|
Updated corpus cached for next run
Workflow 3: Crash Triage and Fix
Crash file identified in findings/
|
Reproduce crash with ASan-instrumented binary
|
Capture ASan stack trace and error type
|
Minimize crash input with afl-tmin
|
Identify root cause from stack trace
|
Develop fix and add crash input as regression test
|
Verify fix by re-running AFL++ with crash input
|
Update corpus to include edge case inputs
Back to mukul975/Anthropic-Cybersecurity-Skills (817 security skills) or Agent skills.