This guide walks you through installing Agentic-AFL, wiring up your environment, and launching a complete fuzzing campaign against an AFL++-instrumented harness. By the end you will have a running campaign with live coverage metrics and a structured JSON result file you can plot and compare across runs.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/AdithyaaSivamal/Agentic-AFL/llms.txt
Use this file to discover all available pages before exploring further.
Prerequisites — confirm these before continuing:
afl-fuzzandafl-ccare on yourPATH(AFL++ 4.x)- Ghidra 11.x is installed, with the path available as
GHIDRA_INSTALL_DIR(default:/opt/ghidra) - Python 3.11 or newer is active in your shell
- A PostgreSQL instance is reachable (Step 3 provides a Docker one-liner)
- An OpenAI or Google Gemini API key is available
Clone and install
Clone the repository and install the package in editable mode. The After installation, verify the CLI is available:
[dev] extra pulls in the test dependencies, the rich TUI library, and python-dotenv for .env loading.Configure environment
Create a To use Google Gemini instead of OpenAI, set:
.env file at the project root. Agentic-AFL’s config module automatically loads this file via python-dotenv on startup. Explicit shell exports always override .env values.Start PostgreSQL
Agentic-AFL uses PostgreSQL to store constraint profiles and Z3 templates for CARM retrieval. The quickest way to get a compatible instance running is with Docker:The schema is initialized automatically on the first
agentic-afl fuzz run. If you already have a PostgreSQL instance, just ensure the POSTGRES_DSN in your .env points to a database that the configured user can create tables in.Compile your harness
Your target must be instrumented with AFL++‘s compiler wrapper so that AFL++ can track edge coverage. Compile exactly as you would with For C++ targets use
gcc or clang, but substitute afl-cc:afl-c++. For targets that require a custom build system, set CC=afl-cc and CXX=afl-c++ in your environment before running the build.Run your first campaign
Launch a one-hour campaign with the rich TUI dashboard enabled. Point The full set of
-i at a directory containing at least one seed file that reaches the first bytes of your target’s parsing logic.fuzz subcommand options:| Flag | Default | Description |
|---|---|---|
--duration | 1h | Campaign wall-clock duration. Accepts 6h, 30m, 90s, or raw seconds. |
--stall-minutes | 5 | Minutes of edge plateau before the agent triggers. |
--accept-marker | ACCEPT | Stdout string that signals a confirmed math wall bypass. |
--custom-mutator | — | Path to a Python AFL++ custom mutator deployed after bypass. |
--log-dir | — | Directory for JSON result files (one file per campaign). |
--name | harness stem | Campaign name used in result filenames and the summary header. |
--tui | off | Enable the rich TUI dashboard (requires the rich package). |
--debug | off | Enable debug logging; also saves raw LLM completions and Z3 scripts to /tmp/agentic_afl_debug/. |
Reading the Output
When--tui is not set, Agentic-AFL prints a columnar dashboard to stdout that updates every 25 seconds:
| Column | Meaning |
|---|---|
| Time | Elapsed campaign time formatted as HhMMmSSs. |
| Edges | Current edges_found from AFL++‘s fuzzer_stats. |
| Execs | Cumulative execs_done from AFL++‘s fuzzer_stats. |
| Stalls | Number of coverage stalls detected so far. |
| Inject | Number of solved payloads injected into the AFL++ sync directory. |
| Status | fuzzing during normal operation; stall×N when stalls are queued; injected×N after successful payload injection. |
--tui is used, the same data is presented in a live Rich panel layout with a pipeline stage indicator (Detect → Ghidra → Profile → CARM → LLM → Z3 → Inject) and a scrolling event log.
Campaign Results
At the end of every campaign (whether the duration expires or you press Ctrl+C), Agentic-AFL prints a structured summary:| Field | Meaning |
|---|---|
| Baseline edges | edges_found from AFL++‘s fuzzer_stats at ~10 seconds into the campaign — represents what AFL++ achieved on its own with the seed corpus. |
| Final edges | edges_found at campaign end — total coverage achieved with Agentic-AFL’s help. |
| Edge gain | Absolute and percentage increase in edges. A large gain after payload injection is the primary indicator that a math wall was bypassed. |
| Stalls detected | How many times the stall detector fired (edge plateau for --stall-minutes). |
| Payloads injected | How many solved Z3 payloads were successfully written to the AFL++ sync directory. |
| LLM calls | Total number of LLM API requests made (each call generates K scripts; multiple ReAct turns may occur per stall). |
| Math wall bypass | ✅ YES if any AFL++ queue entry produced the --accept-marker string when executed against the harness binary. |
| Evidence | The filename of the queue entry that triggered the accept marker — a concrete byte payload that bypasses the math constraint. |
--log-dir is set, the full result is also written as a timestamped JSON file (e.g., harness_20250601_143022.json) containing the complete timeline of edge counts, stall events, and payload injection timestamps.
Visualizing Coverage
Generate a coverage-over-time plot from any campaign JSON result file:timeline array from the JSON file (recorded every ~60 seconds during the campaign) and renders an edge count over time chart. The -o flag is optional — if omitted, the output image is saved with the same name as the JSON file but with a .png extension.