Fuzzing works, but it does not scale without sustained human attention. Coverage analysis, harness writing, and crash triage remain tedious and bottlenecked by human effort. The GitHub Security Lab has released the Fuzzing Taskflow, an autonomous pipeline that hands those repetitive steps to an AI agent while keeping the actual execution in the hands of purpose-built tools.

How It Works

The Fuzzing Taskflow takes a GitHub repository URL and runs an end-to-end fuzzing campaign with no human babysitting. It clones the repository, identifies suitable entry points, analyzes the build system, generates fuzz harnesses, runs AFL++, reads coverage reports, refines the harnesses, triages every crash, and produces a vulnerability report for each unique bug discovered.

The pipeline is built on the GitHub Security Lab Taskflow Agent framework. It uses Claude Sonnet 5 by default, chosen because it passed internal security guardrail tests without issues. The architecture follows a strict separation of responsibility across three layers. A shell driver chains the stages together. Taskflow YAML files define what the agent does at each step. And MCP tools handle the actual execution, such as running AFL, compiling harnesses, and storing crashes.

The agent never calls AFL or clang directly. It composes the pipeline from building blocks exposed by the tools. All state lives in a SQLite database, so stages communicate through that database rather than passing data in memory.

The Coverage Feedback Loop

The core automation is the coverage-feedback loop, which replaces the manual process of reading LCOV reports and writing new harnesses. Each iteration, the agent runs AFL for a time budget, replays the fuzzer queue against a coverage-instrumented binary, and reads the list of uncovered branches.

Based on what it finds, the agent picks one of several actions: add a crafted seed to reach an uncovered branch, edit the harness to call an additional API, enrich the AFL dictionary with magic constants that a guard is comparing against, or skip the gap if it is a cold error path or vendor code that is not worth the effort.

The time budgets double with each iteration: 30 seconds, then 60, 120, 240, 480, and finally 960 seconds per target. The design principle is to spend short, cheap rounds early when there is low-hanging coverage to grab, and longer rounds later when the fuzzer needs more time to penetrate hard guards.

Plateau detection determines when to stop. If two consecutive iterations each gain less than 1% absolute line coverage, the loop concludes it has hit diminishing returns and moves on. This prevents the agent from burning compute on the last fraction of a percent.

Structure-Aware Fuzzing

AFL's default byte-level mutators handle binary formats well but struggle with structured text inputs. Rather than hand-writing custom mutators for each format, the taskflow ships four complementary mechanisms.

First, pre-built per-format dictionaries and custom mutators cover recognized formats like JSON, XML, regex, PNG, and length-prefixed binary TLV. The JSON mutator handles token splicing and balanced-bracket duplication. The XML one knows about tags, entities, and billion-laughs tokens. Each delegates half its mutations back to AFL's default byte mutator.

Second, for formats the pipeline does not recognize, it generates a custom mutator by scanning the target's own source files for string literals and 32-bit numeric constants. Third, a dynamically generated AFL dictionary starts with source tokens and grows after each coverage step by appending tokens found near uncovered lines. Fourth, a corpus-splice operator loads files from a corpus directory and splices random sub-regions into inputs.

Corpus Evolution and Crash Triage

To avoid losing progress between runs, each harness gets a stable corpus directory that persists across iterations and entire campaigns. At the end of each iteration, AFL's queue merges into that directory and is filtered through afl-cmin to keep its size bounded.

After fuzzing completes, the pipeline triages every crash. Each crash is minimized with afl-tmin, replayed under AddressSanitizer to capture a stack trace, and deduplicated by a stack-top hash. Previously known crashes are replayed against the current binary to check whether an upstream fix has resolved them.

The agent then reads the harness source and the crashing function, traces the call chain back from the public API, and writes a per-crash markdown report. Each report receives one of seven verdicts: vulnerability, library_hardening, harness_bug, OOM, timeout, assertion_failure, or duplicate. The reports include root-cause analysis with file and line references, reachability arguments, exploitability assessments, suggested fixes as unified diffs, and regression-test sketches.

The developers are clear that these verdicts are a starting point, not a final result. The agent's analysis depends on its understanding of the target code, and errors do occur. Every suggested patch is marked as review required.

Safety and Limitations

The taskflow runs AFL, clang, and arbitrary build commands directly on the host with no container isolation. A prompt-injected agent could theoretically perform any action the user can. The project documentation explicitly warns against running it in elevated privileges or outside a disposable environment such as a Codespace or throwaway VM.

The Fuzzing Taskflow is open source and available at GitHub. For maintainers of C and C++ projects, whether the project has never been fuzzed or has been fuzzed for years, the tool automates the repetitive work that traditionally limits how much ground a human fuzzer can cover in a campaign.