Coverage-guided fuzzing
Make the real target execute under feedback, with the intended oracle and reproducible lifecycle. A running fuzz binary or growing corpus does not establish useful target reach: "The corpus count value is a bad indicator for checking how good the coverage is" (AFL++ Fuzzing in Depth §3.g).
Select the actual lane
Read the target entrypoint, build graph, enabled features, runtime/architecture, decoder and property. Identify which target modules receive instrumentation and what changes under the fuzz build; a driver-only instrumented path or a feature enabled only on its wrapper can miss the intended implementation. cargo-fuzz feature options "control the fuzz_targets crate" until forwarded, and libFuzzer separates instrumentation (-fsanitize=fuzzer-no-link) from linking its main() (Rust Fuzz Book guide, Cargo features, LLVM libFuzzer, Fuzzer Usage).
Use the existing fitting producer and build owner. Choose only the applicable execution reference:
| Target | Read |
|---|---|
| Native source/binary, AFL++ or libFuzzer | Native runners |
| Go or Rust | Go and Rust |
| Python/native extensions or JVM | Python and JVM |
| C++ property domains with FuzzTest | C++ FuzzTest |
| Node.js (CJS, ESM, TypeScript via Jest) | Node.js with Jazzer.js |
Browser application code has no in-process coverage-guided route: Jazzer.js puts "Other runtimes or browser support" out of scope (Jazzer.js architecture, Constraints). Route browser UI exploration to the skill that owns UI event sequences.
Verify the selected release's prerequisites and installed help before changing configuration. References record a dated source snapshot, not a promise that every version/platform supports the same flags. Invoke within the user's existing authority; this skill does not itself authorize installations, target edits or external spending.
Run a finite informative pilot
Establish discovery mode, relevant target instrumentation, state reset and a working oracle before adding workers. Go seed replay, Jazzer regression, Jazzer.js Jest regression and FuzzTest unit mode differ from their discovery modes: plain go test runs seeds "much like a unit test", "Jazzer operates in regression mode unless fuzzing mode is explicitly enabled", Jazzer.js under Jest defaults to "regression", and FuzzTest unit mode runs "without sanitizer and coverage instrumentation" (Go fuzzing, Running fuzz tests, Jazzer README, Regression mode, Jazzer.js fuzzing settings, mode, FuzzTest Bazel quickstart, Create and run a fuzz test).
Observe decoder admission, intended operation, successful effects and property evaluations separately from engine coverage; byte mutation of a compressed format can leave "virtually all generated inputs to be invalid for uncompress" (Google structure-aware fuzzing guide, Example: Compression). Diagnose rejected formats, hidden state or unmet dependencies using reach, reset and feedback. Select dictionary/comparison feedback or structural mutation against a demonstrated blocker; each changes a different part of search (AFL++ CmpLog, Google structure-aware fuzzing guide).
Keep per-input, fuzz-time, wall-time, worker/CPU and memory controls distinct; include setup/replay cost in the authorized envelope. AFL++ -V is "(fuzz time only!)" and -E is "an approx. no. of total executions"; neither is aggregate process CPU (AFL++ selected-ref CLI source, usage text). Go -timeout does not bound the fuzzing phase (Go and Rust). Use separate owned outputs and bounded cleanup of owned processes; libFuzzer says of exact artifact paths "Do not use the same path for several parallel processes" (LLVM libFuzzer, Options). Refer to bugfinding-campaign for allocation decisions.
Interpret and retain evidence
Preserve exact input/typed arguments, build/configuration/instrumentation, initial state or sequence, command/limits, raw engine output, target/property counters and emitted replay material. Cross-invocation state and lifecycle differences can invalidate one-file reproduction: Go requires that "the state of a fuzz target should not persist past the end of each call", and Jazzer's default PER_TEST is "more likely to unintentionally preserve state between fuzz test executions" (Go fuzzing, Suggestions, Jazzer Lifecycle implementation).
Return what actually executed, the property observed, resource use, candidates and omissions. Distinguish discovery from regression, coverage from semantic reach, and candidate failure from product attribution. Use corpus-evolution for compatible retention/exchange, failure-reduction for witness-preserving shrinking and evidence-based-triage for attribution. Historical seed-selection results depend on their target/scheduler; Rebert et al. found one hypothesis "false under the optimal scheduling" yet tested it again under Round-Robin. Don't turn them into universal throughput or yield promises (Rebert et al., pp.864,871,873).
For concrete misleading runs and corrections, read common mistakes. No target-specific new framework follows from this skill.