Loading...
Loading...
Coverage-guided fuzzing workflow for C/C++, Rust, and Go targets. Runs audit-context-building to find suspicious code, writes a targeted harness, builds with sanitizers, runs the fuzzer, and reports crashes.
npx skill4agent add workersio/spec fuzzeraudit-context-buildingsize_t → intsize_t → uint32_tsize_tfile:linefile:linesize_t→intuint32_t#include <stddef.h>
#include <stdint.h>
#include <string.h>
static const uint8_t kStub[1] = {0};
/* Required by libAFLDriver.a — must be present or link fails */
int LLVMFuzzerInitialize(int *argc, char ***argv) {
(void)argc; (void)argv;
return 0;
}
void LLVMFuzzerCleanup(void) {}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
uint8_t n = data[0] % MAX_CALLS;
if (n == 0 || size < 1 + (size_t)n * 4) return 0;
TargetState *s = TargetState_Create();
for (uint8_t i = 0; i < n; i++) {
uint32_t claimed;
memcpy(&claimed, data + 1 + i * 4, 4);
target_fn(s, (size_t)claimed, kStub); /* claimed drives the arithmetic */
}
TargetState_Destroy(s);
return 0;
}int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < N) return 0;
/* bytes [0..N-1] → config / mode / count */
/* bytes [N..] → payload */
target_fn(config, data + N, size - N);
return 0;
}int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 1) return 0;
target_fn(data, size);
return 0;
}fuzz_target!(|data: &[u8]| { target_function(data); });func FuzzTarget(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) { target_function(data) })
}which afl-clang-fast || find /usr/local /opt/homebrew /tmp -name afl-clang-fast 2>/dev/nullbrew install afl++ # macOS
apt-get install afl++ # Debian/UbuntuAFL=$(which afl-clang-fast)
AFLDRIVER=$(dirname $(dirname $AFL))/lib/afl/libAFLDriver.a
# Compile target sources into instrumented static library
mkdir -p build
find <src-dir> -name "*.c" | while read f; do
$AFL \
-g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer \
<include-flags> -c "$f" -o "build/$(basename $f .c).o"
done
ar rcs build/libtarget.a build/*.o
# Compile harness + link
$AFL \
-g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer \
harness.c build/libtarget.a $AFLDRIVER \
-o build/fuzzercargo fuzz build <target_name>ASAN_OPTIONS=abort_on_error=1:detect_leaks=0:symbolize=0 \
AFL_SKIP_CPUFREQ=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \
$(which afl-fuzz) \
-i corpus/ \
-o findings/ \
-- build/fuzzercargo fuzz run <target_name> corpus/go test -fuzz=FuzzTarget -fuzztime=12h ./...findings/default/crashes/CRASH FOUND
Input: findings/default/crashes/id:000000,...
Signal: sig:06 (SIGABRT = sanitizer) or sig:11 (SIGSEGV)
Reproduce (with symbolized output):
UBSAN_OPTIONS=print_stacktrace=1 \
ASAN_OPTIONS=detect_leaks=0:print_stacktrace=1 \
./build/fuzzer findings/default/crashes/id:000000,...
Sanitizer output:
<paste UBSan/ASan stacktrace here>
Root cause: <file>:<line> — <one sentence description>| Rule | Why |
|---|---|
| Return 0 always | Never abort from the harness itself |
Never call | Kills the fuzzer process |
| Handle all input sizes | Fuzzer generates empty / tiny / huge inputs |
| Be fast — no logging | Target 100–1000+ exec/sec |
| Same input = same output | Determinism required for crash reproduction |
| Free all resources each call | Prevents memory exhaustion over millions of runs |
| Reset global state | Isolates each iteration |
| Target | Fuzzer | Notes |
|---|---|---|
| C / C++ | AFL++ ( | Best coverage instrumentation |
| Rust | | Uses libFuzzer API under the hood |
| Go | | Native, no extra tooling |
| Any binary | AFL++ black-box ( | No source needed |
| Custom / research | LibAFL | Modular Rust fuzzing library |