Safeguard
Security Guides•

Coverage-guided fuzzing explained for beginners

What a coverage-guided fuzzer actually does: mutate inputs, watch which code runs, keep inputs that reach new code, and report crashes with the input.

Safeguard Security Team
3 min read

A coverage-guided fuzzer runs your code with many mutated inputs, watches which parts of the code each input reaches, and keeps the inputs that reach something new. Crashes and sanitizer errors are reported with the input that caused them. It is a feedback loop, not random typing.

The loop in plain words

Start with a few valid inputs, called the seed corpus. The fuzzer picks one, flips bytes, splices pieces together and feeds the result to your function. It measures coverage while the code runs.

If the new input reaches code that no earlier input reached, the fuzzer adds it to the corpus. If not, it throws the input away. Over time the corpus grows into a set of inputs that exercise many branches, including ones a person would never write by hand.

Go's documentation describes the start of a run in these terms: it gathers baseline coverage by executing the seed corpus and the generated corpus, then continues with active fuzzing.

Why feedback matters

Pure random input mostly fails at the first check. A parser that expects a magic number at the start rejects nearly everything, so random data never reaches the interesting code. Coverage feedback lets the fuzzer find the magic number by trial, because a lucky first byte reaches a new branch and gets kept.

What counts as a finding

A crash is the obvious one. In memory unsafe languages, you add sanitizers so that silent corruption becomes a loud error. OSS-Fuzz documentation notes that its fuzzing runs with AddressSanitizer or other sanitizers, and that this adds RAM and CPU overhead.

Timeouts and out of memory conditions are findings too. The same FAQ says that an input needing more than about 25 seconds or 2.5 GB of RAM is reported as a timeout or out of memory bug, because slow inputs reduce fuzzing efficiency.

What you provide

  • A fuzz target: a small function that takes bytes and calls the code under test.
  • Seeds: a handful of valid samples of the format.
  • A way to run it long enough: minutes in CI, hours or days continuously.
  • Someone to read the results.

Where it struggles

Fuzzers are weak where inputs need checksums, signatures or deep protocol state, unless you help by stripping the checksum in the target or writing a structure aware generator. They also cannot tell you a program is correct. A run that finds nothing means these inputs found nothing, not that none exist.

The OSS-Fuzz FAQ lists possible reasons a long run finds nothing, including that all reachable code has been covered. Check coverage reports before concluding the target is clean.

Quick check

Is fuzzing the same as DAST?

No. DAST sends attack style requests to a running web app from outside. Fuzzing here means feeding mutated inputs to a function or binary with coverage feedback, usually in a test harness.

Do I need to write C to use a fuzzer?

No. Go, Rust, Python and Java all have fuzzing tools. The bug classes differ, but the loop is the same.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.