TL;DR: AFL++ campaigns can generate billions of executions and thousands of crashes while still yielding only a handful of real bugs, according to Appknox, because crash volume, coverage, and execution speed do not equal vulnerability discovery. The lesson is that fuzzing pipelines need deduplication, root-cause clustering, and triage discipline before output can be treated as security signal.
At a glance
What this is: This is a practical Appknox guide showing how AFL++ fuzzing at scale turns billions of executions and thousands of crashes into only two real bugs through structured triage.
Why it matters: It matters because security and application teams need to distinguish meaningful exploitability from duplicate crash noise, especially where runtime findings feed broader AppSec, governance, and remediation decisions.
By the numbers:
- Appknox reports that 357 crash files were distilled into 2 actual bugs after triage and deduplication.
- Appknox says persistent mode improved throughput to approximately 394 executions per second per instance.
👉 Read Appknox's analysis of AFL++ fuzzing at scale and crash triage
Context
AFL++ is a coverage-guided fuzzing approach, but output volume alone does not tell teams whether they have found exploitable defects. The first governance problem is interpretation: large crash counts can reflect duplicate execution paths, not distinct vulnerabilities, so security and engineering teams need a triage model that converts noise into risk-relevant findings.
In application security programmes, this matters because runtime testing often feeds vulnerability management, remediation priorities, and reporting to engineering leadership. When crash data is not deduplicated and clustered, teams can overestimate exposure, waste fix cycles, and miss the small number of defects that actually change risk. That pattern is common in mature fuzzing programmes, not an edge case.
Key questions
Q: How should security teams turn fuzzing crashes into actionable risk signals?
A: Security teams should deduplicate crashes by root cause, reproduce them with memory-safety instrumentation, and cluster stack traces before reporting findings. That approach separates repeated trigger paths from unique defects, which makes remediation prioritisation defensible. Without that workflow, crash counts become a volume metric rather than a security metric.
Q: Why do fuzzers generate so many crashes without finding many real bugs?
A: Fuzzers can reach the same defect through many input mutations, so one underlying issue appears as multiple crash files. Parallel workers amplify that duplication. The real measure of value is unique root causes after clustering and reproduction, not the raw number of failures observed during a campaign.
Q: What do teams get wrong about persistent mode in AFL++?
A: Teams often treat persistent mode as a pure speed upgrade, but it only works when the harness resets state correctly between iterations. If cleanup is incomplete, later runs inherit parser state, memory, or counters from earlier runs, which produces misleading results and hides real defects.
Q: How do security teams decide whether to expand fuzzing coverage or tune throughput?
A: Expand coverage when crash volume rises but unique root causes plateau, because that pattern usually means you are retesting the same surface. Tune throughput when the harness still under-exercises the target. The right sequence is validation, persistent optimisation, then surface expansion, with triage running throughout.
Technical breakdown
Why crash volume is a poor proxy for vulnerability count
Coverage-guided fuzzers mutate inputs along many possible paths, so a single bug can surface as hundreds of separate crashes. Parallel instances amplify that effect because each worker may hit the same defect through a different path or seed. Crash counts therefore measure detection frequency, not unique exploitability. To turn fuzzing into a useful control, teams must add deduplication, stack clustering, and reproducible validation so that one root cause is counted once rather than many times.
Practical implication: build triage into the fuzzing workflow before reporting results to engineering or leadership.
Why persistent mode changes fuzzing economics
Persistent mode keeps the target process alive across many iterations instead of restarting it every time, which removes fork overhead and improves throughput materially. That speed gain is not merely operational convenience. It changes how much of the codebase you can exercise within a fixed time window, especially for parser-heavy binaries. The trade-off is state management, because the harness must clean up memory and restore invariants between loops or later iterations become unreliable.
Practical implication: use persistent mode only with harnesses that explicitly reset state between iterations.
How schedule diversity expands coverage without duplicating work
AFL++ power schedules influence how each fuzzer instance spends mutation effort. If every instance uses the same schedule, they converge on similar execution paths and waste CPU on overlapping mutations. Mixed schedules such as explore, exploit, rare, and targeted mutation optimisation push instances into different regions of the input space, which improves the chance of reaching deeper parser logic. The point is not more iterations for their own sake, but more distinct search behaviour.
Practical implication: assign different secondary schedules so parallel fuzzers complement one another instead of competing on the same paths.
Threat narrative
Attacker objective: The attacker aims to trigger real parser defects from crafted archive inputs, exposing a reliable crash or memory corruption condition.
- Entry occurs through attacker-controlled archive input that is parsed by libarchive, giving malformed data a direct path into the parser.
- Escalation happens when multiple input variants trigger the same underlying memory safety or logic flaw across different execution paths.
- Impact is realised when duplicate crashes are collapsed into a small number of unique root causes, revealing actual vulnerabilities that can be exploited for denial of service or deeper compromise.
NHI Mgmt Group analysis
Crash triage is a governance control, not a cleanup task. The article shows that fuzzing output becomes meaningful only when organisations separate duplicate crashes from unique defects. In practice, that means crash deduplication, stack clustering, and reproducible validation are part of the security control set, not a post-processing convenience. Teams that stop at crash counts are measuring activity, not exposure.
Execution speed without interpretation creates false assurance. 8.5 billion executions sounds impressive, but the post’s core lesson is that throughput does not equal risk reduction. Security programmes should treat fuzzing as an evidence-generation workflow where the question is not how much ran, but how many distinct root causes survived triage. That is the difference between high-volume testing and defensible vulnerability management.
Persistent harness quality is the real control boundary. The article makes clear that persistent mode, CmpLog, LTO, and schedule diversity only work when the harness preserves state correctly and reaches deep parser surfaces. In other words, the security value sits in the harness architecture and experiment design, not in raw tool use. Practitioners should view fuzzing quality as an engineering maturity issue.
Noise-to-signal is now a broader AppSec pattern. The same discipline that reduces fuzzing crashes to real bugs also applies to alerts, scanner findings, and runtime telemetry. Organisations that cannot collapse duplicate security output will struggle to prioritise remediation across AppSec, cloud, and identity workflows. The practical conclusion is to build triage logic into every detection-heavy control, not just fuzzing.
What this signals
Noise-to-signal discipline is becoming a security management requirement, not a lab technique. The same pattern that applies to fuzzing applies to vulnerability scanners, cloud detectors, and identity telemetry. If teams cannot collapse duplicates and isolate root causes, they will over-prioritise volume over exposure and under-resource the controls that actually reduce risk.
For identity-led programmes, the lesson is familiar even when the domain is not. The distinction between output and actionable risk is central to NHI governance, where visibility only matters if it leads to lifecycle action. That is why the Ultimate Guide to NHIs remains relevant to broader security operations: it frames how excess exposure becomes operationally meaningful, not just numerically large.
Security leaders should expect more engineering and security overlap in remediation workflows. Fuzzing, AppSec, cloud posture, and identity governance all depend on the same executive question: which findings are unique enough to justify action? Organisations that answer that well will move faster without inflating their risk picture.
For practitioners
- Add crash deduplication before vulnerability reporting Cluster AFL++ crashes by stack trace and reproduce them with ASAN before counting them as unique findings. That prevents duplicate crash files from inflating risk registers and keeps remediation focused on root causes.
- Use persistent mode only with state-resetting harnesses Implement persistent loops so the target stays in memory across iterations, but reset allocated state, buffers, and parser context on every pass. Without clean state handling, throughput gains produce unreliable results.
- Mix mutation schedules across secondary instances Assign different power schedules such as explore, exploit, rare, and one MOpt instance so parallel fuzzers do not converge on the same mutation path. Diverse schedules improve coverage efficiency.
- Treat deeper parser surfaces as distinct test targets Expand from CLI validation into nested object graphs, metadata traversals, sparse regions, and iterator-heavy code paths. Those surfaces are where new crash classes emerge after basic paths plateau.
- Build a triage pipeline into AppSec operations Feed reproducible crashes into CASR or equivalent clustering, then route only unique root causes into engineering workflows. That turns fuzzing from a volume exercise into a prioritised defect discovery process.
Key takeaways
- A large number of crashes does not prove a large number of vulnerabilities, because fuzzers often hit the same defect through many paths.
- Persistent mode, schedule diversity, and deeper surfaces improve discovery only when triage reduces duplicates to unique root causes.
- The operational lesson is to treat deduplication and clustering as core security controls, not optional cleanup after testing.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
MITRE ATT&CK address the attack and risk surface, while NIST CSF 2.0, NIST SP 800-53 Rev 5 and CIS Controls v8 set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| NIST CSF 2.0 | DE.CM-7 | Crash triage and validation support continuous security monitoring and detection analysis. |
| NIST SP 800-53 Rev 5 | SI-2 | The article is about finding and validating software flaws before they become exploitable. |
| MITRE ATT&CK | TA0009 , Collection; TA0040 , Impact | Malformed archive inputs can trigger parser failures that lead to denial of service or deeper compromise. |
| CIS Controls v8 | CIS-16 , Application Software Security | Fuzzing and crash triage are core application security practices covered by CIS guidance. |
Map parser-driven crash paths to ATT&CK impact tactics and prioritise the inputs that reproduce unique faults.
Key terms
- Crash Deduplication: Crash deduplication is the process of grouping repeated failures that stem from the same underlying bug. In fuzzing, it prevents one defect from being counted many times and helps teams focus on unique root causes that actually change security posture.
- Persistent Mode: Persistent mode is a fuzzing execution pattern where the target stays alive across many test iterations instead of restarting each time. It improves throughput, but it only produces reliable results when the harness correctly resets state between loops.
- Power Schedule: A power schedule determines how a fuzzer allocates mutation effort across inputs and execution paths. Different schedules can bias discovery toward new coverage, rare edges, or promising states, which matters when multiple instances fuzz in parallel.
- CmpLog: CmpLog is an AFL++ feature that records runtime comparisons so the fuzzer can learn which values are blocking path discovery. It is useful for structured inputs with magic bytes, checksums, and parser constraints that ordinary mutation struggles to satisfy.
What's in the full article
Appknox's full blog covers the operational detail this post intentionally leaves for the source:
- Step-by-step AFL++ harness setup, including the native, ASAN, and CmpLog build matrix used in the campaign
- Concrete command-line examples for CLI validation, persistent mode, and mixed secondary schedules
- Crash triage workflow details showing how CASR, stack clustering, and reproduction reduced 1,166 crashes to 2 bugs
- Phase-by-phase performance and corpus growth numbers for teams benchmarking their own fuzzing pipelines
👉 The full Appknox post covers harness design, execution tuning, and crash clustering in detail
Deepen your knowledge
The NHI Foundation Level course, the industry's only accredited NHI security programme, covers NHI governance, identity lifecycle, and secrets management in a way that complements engineering-led security work. It is designed for practitioners who need to connect identity control with broader remediation and assurance programmes.
Published by the NHIMG editorial team on August 18, 2026.
NHI Mgmt Group — the independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org