FR
live

GitHub Security Lab ships an agent that fuzzes a C/C++ repo end to end

On 24 September 2026, GitHub Security Lab released an autonomous fuzzing pipeline that writes its own harnesses, reads its own coverage and drafts its own vulnerability reports. The fuzzing bottleneck — human attention — is handed to an LLM, but the code runs on the host with no container in between.

A fine metal needle grazing the dark surface of a silicon chip, a single contact point glowing amber.

24 September 2026. Antonio Morales, a researcher at the GitHub Security Lab, publishes the Fuzzing Taskflow, an autonomous fuzzing pipeline for C/C++ projects. 2014. Michal Zalewski released AFL, the coverage-guided fuzzer that popularised the discipline. 2016. Google launched OSS-Fuzz, industrialising continuous fuzzing of open source. Why it matters: the fuzzing bottleneck was never compute, but human attention — and that attention is exactly what this pipeline hands to an LLM, from the first harness to the vulnerability report.

A pipeline that goes from repo to report

The Fuzzing Taskflow is built on the GitHub Security Lab’s Taskflow Agent framework for LLM-driven security automation. The pitch fits in one sentence: point it at a GitHub repository and it does the rest.

In concrete terms, the agent identifies the relevant entry points, analyses the build system, writes the harnesses, runs AFL++, reads coverage reports, improves the harnesses, triages every crash and writes a vulnerability report for each distinct bug — with no human babysitting between stages. The announcement’s example is telling: run the campaign against xz, the project whose backdoor shook the supply chain in 2024, or against cJSON for a quick smoke test.

bash
git clone https://github.com/GitHubSecurityLab/seclab-taskflows-fuzzing
cd seclab-taskflows-fuzzing
./scripts/fuzzing/run_fuzzing.sh tukaani-project/xz

The architecture comes in three layers. A shell driver, run_fuzzing.sh, chains the pipeline stages together. A set of taskflow YAML files — one per stage — carry the prompts that tell the agent what to do at each step. A set of MCP tools does the actual work: running AFL, compiling a harness, storing a crash, reading a coverage report. The stated design rule is a strict separation of responsibilities: the LLM owns the decisions, the tools own the execution. The agent never calls AFL or clang directly; it composes the pipeline out of those primitives. All state flows through a SQLite database, fuzz_context.db, never through shared memory between stages.

The coverage loop, the heart of the system

The part that most faithfully automates the manual workflow is the coverage loop. Improving fuzzing coverage by hand is a familiar cycle: measure coverage, hunt down uncovered branches, then write a harness or seed to reach them. The Fuzzing Taskflow hands both steps to the agent.

Each iteration, for each harness, the agent runs AFL on a time budget, replays the queue against the coverage binary to get a real report, then reads the list of uncovered branches. It then picks an action from a small set: add a seed crafted to reach a branch, edit the harness to call an additional API, enrich the AFL dictionary with the magic constants a comparison checks against, or simply skip the gap if it is a cold error path or vendor code not worth chasing.

Time budgets double every iteration — 30 s, 60 s, 120 s, 240 s, 480 s, 960 s, roughly 32 minutes per target. The idea is to spend cheap, short rounds early, when low-hanging coverage is abundant, then long rounds when the fuzzer must break through a hard guard. Stopping is governed by plateau detection: once two consecutive iterations each gain less than a configurable threshold — 1 % absolute line coverage by default — the loop decides it has hit diminishing returns and moves on.

A fuzzer that understands format structure

AFL’s byte-level mutations excel on binary formats but struggle with structured, text-based inputs. The pipeline ships four complementary mechanisms for producing structure-aware inputs.

For recognised formats — JSON, XML, regular expressions, PNG, length-prefixed TLV binary — it delivers pre-built AFL dictionaries and LLVMFuzzerCustomMutator C files. The JSON mutator does token splicing and balanced-bracket duplication; the XML one knows about tags, entities and billion-laughs tokens; the regex one carries real ReDoS patterns. Each mutator delegates half its mutations back to the default byte mutator, keeping the engine’s randomness instead of fighting it.

For formats the pipeline does not recognise, it generates a custom mutator on the fly by scanning the target’s own .c/h files, extracts string literals and 32-bit numeric constants, then uses them as splice tokens. The intuition is simple: the most interesting magic values a parser checks for are usually written down somewhere in its own source. A corpus-splice operator rounds out the set, recombining sub-regions of existing files in a way AFL’s stock havoc does not do well.

Crash triage, now automated

Finding a crash is only half the job. Triage — often the most tedious part — is the other place the agent shines. Three stages run after the fuzzing loop finishes.

Each crash is minimised with afl-tmin, replayed under ASan to capture a stack trace, then deduplicated by a stack-top hash — normalised frames, with templates, inline namespaces and LTO suffixes stripped so semantically identical crashes collapse together. Previously known crashes are replayed against the current binary to see whether an upstream fix has resolved them. Finally, the agent reads the harness and the crashing function, walks the call chain back from the public API, and writes a Markdown report per crash, assigning a verdict from vulnerability, library_hardening, harness_bug, OOM, timeout, assertion_failure and duplicate.

The distinction between a real vulnerability — reachable and exploitable through a public API — and a mere harness_bug is exactly the judgement call that used to require tracing the code by hand. Every report includes a root-cause analysis with file:line references, a reachability argument, an exploitability assessment, a suggested fix as a unified diff and a regression-test sketch. The author is candid about a limit: the suggested patches are marked “review required”, because the agent’s analysis is bounded by the model’s understanding of the target code — and it does get things wrong.

The limit the author owns: no container

One warning, placed before even the usage instructions, deserves the full attention of any CISO or SRE. This taskflow runs afl-fuzz, clang and arbitrary build commands chosen by the LLM directly on the host, with no container in between. A prompt-injected agent could, in principle, do anything your user can.

The author’s recommendation is unambiguous: run it only inside a disposable environment — a Codespace or a throwaway VM — and without elevated privileges. The default model is Claude Sonnet 5, chosen because it passed all internal tests without issues. The author also notes a live HTML dashboard, published on port 8765, lets you follow the campaign in real time — a per-harness pulse, a coverage-trend table with sparklines, a crash heatmap and an iteration timeline.

Verdict

If you maintain a C/C++ project, try it on a repo that has never been fuzzed: it is the shortest path to a first harness and a first crash triage, and the code is open. If your project is already in OSS-Fuzz, the value is elsewhere — raising coverage by letting the agent chase branches your harnesses never reach. In every case, run it in a disposable VM without privilege escalation and treat each of the agent’s verdicts as a well-prepared starting point for a human, never as a conclusion. The wider lesson outlives this project: when you hand a security pipeline to an LLM, keep the separation of responsibilities — the agent decides, your tools execute, and you review.

References

The cyber brief, every Tuesday

The flaws that matter and the patches to apply, in a ten-minute read.

No spam. One-click unsubscribe.
read next

On the same topic

OpenTelemetry and Prometheus finally converge, and the 2026 numbers confirm it

A 2026 survey shows interoperability between OpenTelemetry and Prometheus has improved markedly: the ease-of-use score climbed from 3.1 to 3.6, and the share who find them hard to combine fell from 29% to 10%. For an SRE team still on the fence, now is the time to consolidate on the OTel Collector without abandoning Prometheus.

A leaked GitLab work-item email lets anyone open merge requests in your name

On September 24, 2026, Aikido revealed that GitLab’s “Email work item to this project” addresses, generated with a long-lived token and accidentally published in READMEs, let an attacker open merge requests or push code as the token owner. Search your repositories for these addresses and reset the exposed tokens.

← Back to the feed

Type at least two characters.

↑ ↓ navigate ↵ open esc dismiss