Secure fuzz testing
Koleksi 20 Claude Skills siap pakai untuk pengembangan SaaS, web modern, dan praktik rekayasa perangkat lunak tingkat lanjut.
npx -y skills add roedyrustam/claudevibeskills --skill secure-fuzz-testingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Coverage-guided fuzzing with Atheris, cargo-fuzz, and native Go fuzzing, combined with compilers/sanitizers (ASan, MSan, UBSan) for security validation. Use whenever the user wants to fuzz test code, find memory safety bugs, validate parsers/deserializers against malformed input, or harden security-critical code paths. Trigger on mentions of fuzzing, fuzz testing, AddressSanitizer, libFuzzer, cargo-fuzz, Atheris, go test -fuzz, or security validation of parsing/deserialization logic.
SKILL.md
9.0 KB, as published. Nobody here has run it
Secure Fuzz Testing
Coverage-guided fuzzing across Python, Rust, and Go with sanitizer integration.
Why Fuzz
Fuzzing finds bugs unit tests miss: crashes, panics, memory corruption, infinite loops, and logic errors triggered by malformed or unexpected input. Critical for any code that parses untrusted input — file formats, network protocols, deserializers, APIs.
Python Fuzzing with Atheris
Setup
uv add --dev atheris
Basic Fuzz Harness
# fuzz/fuzz_parser.py
import atheris
import sys
with atheris.instrument_imports():
from myapp.parser import parse_config
def TestOneInput(data: bytes) -> None:
fdp = atheris.FuzzedDataProvider(data)
text = fdp.ConsumeUnicodeNoSurrogates(fdp.remaining_bytes())
try:
parse_config(text)
except (ValueError, KeyError):
pass # Expected exceptions — not bugs
# Anything else (TypeError, IndexError, unhandled) = potential bug
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()
# Run fuzzing
python fuzz/fuzz_parser.py
# With a corpus directory (saves interesting inputs)
mkdir corpus
python fuzz/fuzz_parser.py corpus/
# Limit runtime
python fuzz/fuzz_parser.py -max_total_time=300 # 5 minutes
# Reproduce a crash
python fuzz/fuzz_parser.py crash-<hash>
Structured Fuzzing (JSON-like inputs)
import atheris
import json
def TestOneInput(data: bytes) -> None:
fdp = atheris.FuzzedDataProvider(data)
# Build structured input from fuzz bytes
payload = {
"user_id": fdp.ConsumeIntInRange(-1000, 1000000),
"name": fdp.ConsumeUnicodeNoSurrogates(50),
"active": fdp.ConsumeBool(),
"tags": [fdp.ConsumeUnicodeNoSurrogates(20) for _ in range(fdp.ConsumeIntInRange(0, 5))],
}
try:
validate_user_payload(payload)
except ValidationError:
pass
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()
Rust Fuzzing with cargo-fuzz
Setup
cargo install cargo-fuzz
cargo fuzz init
Fuzz Target
// fuzz/fuzz_targets/parse_input.rs
#![no_main]
use libfuzzer_sys::fuzz_target;
use myapp::parser::parse_config;
fuzz_target!(|data: &[u8]| {
if let Ok(s) = std::str::from_utf8(data) {
let _ = parse_config(s); // panics are caught and reported as crashes
}
});
Structured Fuzzing with arbitrary
// fuzz/fuzz_targets/structured.rs
#![no_main]
use libfuzzer_sys::fuzz_target;
use arbitrary::Arbitrary;
#[derive(Arbitrary, Debug)]
struct UserPayload {
id: u32,
name: String,
age: u8,
tags: Vec<String>,
}
fuzz_target!(|payload: UserPayload| {
let _ = validate_user(&payload);
});
# fuzz/Cargo.toml
[dependencies]
libfuzzer-sys = "0.4"
arbitrary = { version = "1", features = ["derive"] }
myapp = { path = ".." }
Running with Sanitizers
# AddressSanitizer (default) — detects memory corruption
cargo fuzz run parse_input
# Run for a fixed duration
cargo fuzz run parse_input -- -max_total_time=300
# Run with a larger corpus
cargo fuzz run parse_input fuzz/corpus/parse_input/
# MemorySanitizer — detects uninitialized memory reads
RUSTFLAGS="-Z sanitizer=memory" cargo fuzz run parse_input
# Minimize a crashing input
cargo fuzz tmin parse_input fuzz/artifacts/parse_input/crash-<hash>
# Reproduce a specific crash
cargo fuzz run parse_input fuzz/artifacts/parse_input/crash-<hash>
Go Native Fuzzing
Fuzz Test (Go 1.18+, built-in)
// parser_fuzz_test.go
package parser
import "testing"
func FuzzParseConfig(f *testing.F) {
// Seed corpus — known valid/edge-case inputs
f.Add("key=value")
f.Add("")
f.Add("key=")
f.Add(`key="quoted value"`)
f.Fuzz(func(t *testing.T, input string) {
result, err := ParseConfig(input)
if err != nil {
return // expected error — not a bug
}
// Invariant checks
if result == nil {
t.Errorf("ParseConfig returned nil with no error for input: %q", input)
}
// Round-trip property: parse(serialize(x)) == x
serialized := result.Serialize()
reparsed, err := ParseConfig(serialized)
if err != nil {
t.Errorf("Failed to reparse serialized output: %v", err)
}
if !reparsed.Equals(result) {
t.Errorf("Round-trip mismatch for input: %q", input)
}
})
}
# Run fuzzing
go test -fuzz=FuzzParseConfig -fuzztime=60s
# Run with sanitizer (requires CGO + clang)
go test -fuzz=FuzzParseConfig -fuzztime=60s -gcflags=all=-d=checkptr
# Crashes saved automatically to testdata/fuzz/FuzzParseConfig/
# Re-run with: go test -run=FuzzParseConfig/<seed>
Sanitizers Reference
| Sanitizer | Detects | Use With |
|---|---|---|
| ASan (AddressSanitizer) | Buffer overflows, use-after-free, double-free | C/C++/Rust |
| MSan (MemorySanitizer) | Uninitialized memory reads | C/C++/Rust (Clang) |
| UBSan (UndefinedBehaviorSanitizer) | Integer overflow, null deref, type confusion | C/C++/Rust |
| TSan (ThreadSanitizer) | Data races, deadlocks | Concurrent code |
C/C++ with libFuzzer + Sanitizers
# Compile with multiple sanitizers
clang++ -g -O1 -fsanitize=address,fuzzer,undefined \
-fsanitize-address-use-after-scope \
fuzz_target.cc -o fuzz_target
./fuzz_target -max_total_time=300 corpus/
Building Effective Fuzz Harnesses
Good Harness Checklist
- Targets a single, well-defined function or parsing boundary
- Catches expected errors (don't report them as crashes)
- Includes a seed corpus of realistic valid + edge-case inputs
- Checks invariants, not just "doesn't crash" (round-trip, idempotency)
- Runs fast (microseconds per iteration) — slow targets fuzz poorly
- Deterministic — same input always produces same behavior
What to Fuzz First (Priority Order)
- Parsers — JSON, YAML, config files, binary formats
- Deserializers — anything from
bytes→ struct - Network protocol handlers — anything reading from sockets
- Compression/decompression — zip, gzip bombs, decompression ratio attacks
- Auth token / JWT parsing — malformed tokens shouldn't panic
- Regular expressions — catastrophic backtracking (ReDoS)
- Path/URL handling — path traversal via malformed input
CI Integration
# .github/workflows/fuzz.yml
name: Fuzz Testing
on:
schedule:
- cron: '0 2 * * *' # nightly
pull_request:
paths:
- 'src/parser/**'
jobs:
fuzz-rust:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- run: cargo install cargo-fuzz
- name: Run fuzz targets (5 min each)
run: |
for target in $(cargo fuzz list); do
cargo fuzz run $target -- -max_total_time=300
done
fuzz-go:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- name: Run Go fuzz tests
run: go test -fuzz=Fuzz -fuzztime=60s ./...
Triaging Fuzz Findings
# 1. Minimize the crashing input (find smallest reproducer)
cargo fuzz tmin <target> <crash-file>
# 2. Get a backtrace
RUST_BACKTRACE=full cargo fuzz run <target> <crash-file>
# 3. Classify the bug:
# - Panic/crash → DoS risk, fix immediately
# - Memory corruption (ASan) → CRITICAL, potential RCE
# - Logic error (wrong output, no crash) → correctness bug
# - Infinite loop/hang → DoS risk (add timeout, fix complexity)
# 4. Write a regression test from the minimized crash
# Add the crashing input to your seed corpus permanently
Key Rules
- Fuzz parsers and deserializers first — highest bug density, highest risk
- Catch expected errors in the harness — don't waste cycles on known-invalid input paths
- Always minimize crashes before filing/fixing — smaller reproducers are easier to debug
- Run ASan by default — it's nearly free and catches the most dangerous bugs
- Seed corpus matters — start fuzzing from realistic inputs, not just empty/random
- Check invariants, not just crashes — round-trip properties catch logic bugs
- Time-box CI fuzzing — 1-5 min per target in PR CI, longer runs nightly
- Every fixed crash becomes a permanent corpus entry — prevents regression
- Fuzz before every major release — especially after touching parsing code
- Treat OOM and timeouts as bugs too — not just crashes/panics