2026-04-06ยท11 min readยทsota.io team

Deploy AFL++ to Europe โ€” Andrea Fioraldi ๐Ÿ‡ฎ๐Ÿ‡น (EURECOM โ†’ CISPA) + Dominik Maier ๐Ÿ‡ฉ๐Ÿ‡ช (TU Berlin โ†’ CISPA Helmholtz Center Saarbrรผcken), the Dominant Coverage-Guided Fuzzer Behind Thousands of CVEs, on EU Infrastructure in 2026

Coverage-guided fuzzing has become the most effective technique for finding exploitable vulnerabilities in real-world software. Not formal verification โ€” not manual code review โ€” but automated, randomised input mutation guided by program coverage feedback. The dominant tool in this space is AFL++, developed at CISPA Helmholtz Center for Information Security in Saarbrรผcken, Germany: a community-driven successor to Google engineer Michal Zalewski's AFL that has absorbed every significant research advance in coverage-guided fuzzing into a single, extensible framework.

Andrea Fioraldi ๐Ÿ‡ฎ๐Ÿ‡น completed his PhD at EURECOM ๐Ÿ‡ซ๐Ÿ‡ท (Sophia Antipolis, France) and then joined CISPA as a postdoctoral researcher. Dominik Maier ๐Ÿ‡ฉ๐Ÿ‡ช came from TU Berlin ๐Ÿ‡ฉ๐Ÿ‡ช to CISPA. Together with Heiko EiรŸfeldt ๐Ÿ‡ฉ๐Ÿ‡ช (Intel security researcher, Munich) and Marc Heuse ๐Ÿ‡ฉ๐Ÿ‡ช (Berlin-based security researcher), they published "AFL++: Combining Incremental Steps of Fuzzing Research" at the USENIX Workshop on Offensive Technologies (WOOT) 2020. The paper unified the fragmented landscape of AFL forks โ€” AFLFast, AFL-Dyninst, TriforceAFL, CollAFL, FairFuzz, Angora, and others โ€” into a single codebase that empirically outperforms all of them.

CISPA (Center for IT-Security, Privacy and Accountability) is a member of the Helmholtz Association of German Research Centers โ€” Germany's largest scientific organisation, funded by the Federal Ministry of Education and Research (BMBF) and the State of Saarland. CISPA has a specific mandate to produce practical security tools that protect European digital infrastructure. AFL++ is the most deployed output of that mandate: it is the default fuzzer for Google OSS-Fuzz, the program that continuously fuzzes hundreds of open-source projects depended upon by EU public services and industry.

Coverage-Guided Fuzzing: The Core Principle

AFL++ implements coverage-guided greybox fuzzing (CGF). The algorithm is:

  1. Start with a seed corpus of valid inputs
  2. Mutate an input from the corpus
  3. Execute the target with the mutated input
  4. Measure coverage (which basic blocks were executed)
  5. If the mutation reached new coverage, add it to the corpus
  6. Repeat until a crash or timeout

The coverage measurement uses SHM (shared memory) bitmap feedback: the target is compiled with instrumentation that writes a 64KB bitmap; each byte records whether a specific edge (source โ†’ destination basic block transition) was exercised. AFL++ checks whether any byte changed after each execution. If new edges appear, the input is "interesting" and enters the corpus as a seed for further mutation.

This feedback loop means AFL++ automatically discovers the deep paths through complex parsers, protocol implementations, and state machines โ€” without requiring any knowledge of the input format.

What Makes AFL++ Different from AFL

The original AFL by Michal Zalewski (2013โ€“2017) established the paradigm. AFL++ (2019โ€“present) adds:

CmpLog: Breaking Magic Bytes

Many programs reject inputs with invalid magic bytes, checksums, or exact-match strings. Classical AFL cannot guess that if (val == 0xDEADBEEF) requires a specific 4-byte sequence โ€” random mutation has a 1 in 4 billion chance of hitting it.

CmpLog solves this by instrumenting all comparison instructions at the LLVM level: every icmp instruction records both operands into a log. AFL++ then replays the log and splices the comparison operands into future mutations โ€” directly breaking the magic byte barrier. This technique was originally from Angora (2018, Peng Chen + Hao Chen, UC Davis), but AFL++ integrates it into the full pipeline with no configuration required.

# Enable CmpLog instrumentation
AFL_LLVM_CMPLOG=1 afl-clang-fast -o target_cmplog target.c

# Run with CmpLog secondary instance
afl-fuzz -i seeds -o out -c target_cmplog -- ./target @@

LAF-Intel: Splitting Multi-Byte Comparisons

LAF-Intel (LLVM-AFL Feedback-Driven Fuzzer) transforms multi-byte comparison operations at compile time into chains of single-byte comparisons. Instead of if (val == 0xDEADBEEF), the compiler produces:

if (byte0 == 0xDE && byte1 == 0xAD && byte2 == 0xBE && byte3 == 0xEF)

Each byte comparison is a separate coverage edge. AFL++ can now incrementally satisfy the full comparison โ€” each partial match produces new coverage and advances the corpus toward the target state. This works for both integer comparisons and string comparisons (strcmp, strncmp, memcmp).

AFL_LLVM_LAF_ALL=1 afl-clang-fast -o target_laf target.c

MOpt: Mutation Operator Scheduling

AFL has seven core mutation operators: bit flip, byte flip, arithmetic, interesting values, dictionary substitution, splice, and havoc. The original AFL uses a fixed schedule. MOpt (Mutation Operator Optimisation, from Chenyang Lyu et al., CCS 2019) uses Particle Swarm Optimisation (PSO) to dynamically allocate fuzzing time to the mutation operators that are currently producing the most new coverage.

In AFL++, MOpt runs as a secondary mode alongside the main fuzzer. As the fuzzing campaign progresses and the easy coverage has been found, MOpt shifts resources toward the operators that are still finding new paths.

afl-fuzz -i seeds -o out -L 0 -- ./target @@  # Enable MOpt

Custom Mutators API

AFL++ provides a C and Python API for plugging in domain-specific mutators. This is the key to fuzzing structured inputs โ€” network protocols, serialisation formats, image codecs, cryptographic handshakes โ€” where random bit flips produce inputs that are immediately rejected before reaching the interesting code.

// custom_mutator.c โ€” domain-aware mutator
#include "custom_mutator_helpers.h"

size_t afl_custom_fuzz(void *data, uint8_t *buf, size_t buf_size,
                       uint8_t **out_buf, uint8_t *add_buf,
                       size_t add_buf_size, size_t max_size) {
  // Parse input as your protocol
  // Mutate semantic fields (not raw bytes)
  // Return modified buffer
}

The Python API allows rapid prototyping: write a mutator in Python that understands your wire format, and AFL++ will call it for each mutation cycle alongside its own havoc mutations.

Power Schedules

AFL++ implements seven power schedules that control how much fuzzing energy (number of mutations) to allocate to each corpus entry:

ScheduleStrategy
exploitPrioritise seeds near crash boundaries
fastAFL's original schedule (frequency-based)
coeFavour rare-coverage seeds (CoE from CollAFL)
rareMaximise rare-edge exploration
seekBalance between exploit and rare
quadQuadratic energy scaling
linLinear energy scaling

The default is fast. For long campaigns on complex targets, coe or rare often finds more unique crash paths by preventing the fuzzer from spending all its energy on already-well-covered seeds.

Instrumentation Modes

AFL++ supports multiple instrumentation strategies:

CC=afl-clang-fast CXX=afl-clang-fast++ ./configure && make
afl-fuzz -i seeds -o out -- ./target @@

LLVM mode compiles persistent-mode harnesses, supports CmpLog and LAF-Intel, and achieves the highest throughput via in-process fuzzing without process restart overhead.

QEMU Mode (Black-box)

# No source code required
afl-fuzz -Q -i seeds -o out -- ./target_binary @@

QEMU mode uses dynamic binary translation to inject coverage instrumentation into closed-source binaries. Throughput is 5โ€“10ร— lower than LLVM mode but enables fuzzing firmware, proprietary libraries, and legacy systems.

Persistent Mode

// Fuzz harness โ€” eliminates fork() overhead
__AFL_FUZZ_INIT();
int main() {
  while (__AFL_LOOP(1000)) {
    uint8_t *buf = __AFL_FUZZ_TESTCASE_BUF;
    size_t len = __AFL_FUZZ_TESTCASE_LEN;
    // Call target with buf/len
  }
}

Persistent mode runs thousands of test cases in a single process instance, eliminating the overhead of fork() + execve() for each input. For targets with expensive initialisation (loading libraries, opening databases), this can improve throughput by 10โ€“100ร—.

Production Deployments: OSS-Fuzz and Linux Kernel

Google OSS-Fuzz

OSS-Fuzz continuously fuzzes 1,000+ open-source projects โ€” including OpenSSL, curl, libpng, FreeType, SQLite, FFmpeg, WebRTC, and hundreds of others. AFL++ is the default fuzzer for OSS-Fuzz projects that support coverage instrumentation. Every EU software organisation that uses these libraries benefits from the bugs AFL++ has already found in them.

Since 2016, OSS-Fuzz has found over 10,000 vulnerabilities. AFL++ accounts for a significant fraction: the fuzzer's CmpLog and LAF-Intel capabilities consistently outperform purely random mutation on projects with structured inputs.

# OSS-Fuzz project.yaml example
language: c++
fuzzing_engines:
  - afl      # AFL++ is selected when engine=afl
sanitizers:
  - address
  - memory
  - undefined

Linux Kernel (syzkaller + AFL++)

The Linux kernel's syzbot continuous fuzzing infrastructure uses syzkaller as the primary syscall fuzzer. AFL++ complements syzbot for kernel components that accept structured file format inputs โ€” filesystems (ext4, btrfs, f2fs), network protocol parsers, and device drivers.

Kernel fuzzing with AFL++ uses QEMU + KVM for full isolation: each fuzzing instance runs an entire virtual machine, and crashes in the guest are collected automatically. CISPA researchers have used this setup to find vulnerabilities in the Linux kernel eBPF verifier, network socket implementations, and filesystem drivers.

OpenSSL, curl, libpng

Community AFL++ usage has produced thousands of CVEs in widely-deployed libraries:

Running AFL++

# Build with LLVM instrumentation
CC=afl-clang-fast CXX=afl-clang-fast++ \
  CFLAGS="-fsanitize=address" CXXFLAGS="-fsanitize=address" \
  ./configure --disable-shared && make -j$(nproc)

# Prepare seed corpus
mkdir seeds
echo "AAAA" > seeds/seed1
cp /usr/share/doc/target/example.* seeds/ 2>/dev/null || true

# Run single instance
afl-fuzz -i seeds -o out -m none -- ./target @@

# Run parallel (one per core recommended)
# Master
afl-fuzz -i seeds -o out -M fuzzer01 -- ./target @@
# Workers
afl-fuzz -i seeds -o out -S fuzzer02 -- ./target @@
afl-fuzz -i seeds -o out -S fuzzer03 -- ./target @@

# Check status
afl-whatsup out/

Reading AFL++ Output

american fuzzy lop ++ 4.10c {fuzzer01} (./target) [fast]
โ”Œโ”€ process timing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚        run time : 0 days, 1 hrs, 23 min, 12 sec      โ”‚
โ”‚   last new find : 0 days, 0 hrs, 0 min, 7 sec        โ”‚
โ”‚ last uniq crash : 0 days, 0 hrs, 12 min, 33 sec      โ”‚
โ”œโ”€ overall results โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚         cycles done : 3                              โ”‚
โ”‚    corpus count : 247                                โ”‚
โ”‚   saved crashes : 8                                  โ”‚
โ”‚  saved hangs : 1                                     โ”‚
โ”œโ”€ cycle progress โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  now processing : 187.6/247 (75.7%)                  โ”‚
โ”‚  runs timed out : 0 (0.00%)                          โ”‚
โ”œโ”€ map coverage โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚   map density : 3.91% / 4.02%                       โ”‚
โ”‚  count coverage : 3.25 bits/tuple                    โ”‚
โ”œโ”€ findings in depth โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ favored items : 28/247 (11.34%)                      โ”‚
โ”‚  new edges on : 28/247 (11.34%)                      โ”‚
โ”‚ total crashes : 12 (8 unique)                        โ”‚
โ”‚  total hangs : 7 (1 unique)                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

CI/CD Integration

# .github/workflows/fuzz.yml
name: AFL++ Fuzzing
on:
  schedule:
    - cron: '0 2 * * *'  # nightly
  workflow_dispatch:

jobs:
  fuzz:
    runs-on: ubuntu-latest
    container: aflplusplus/aflplusplus:latest
    timeout-minutes: 120
    steps:
      - uses: actions/checkout@v4
      
      - name: Build with AFL++ instrumentation
        run: |
          CC=afl-clang-fast CXX=afl-clang-fast++ \
          CFLAGS="-fsanitize=address,undefined" \
          CXXFLAGS="-fsanitize=address,undefined" \
          ./configure --disable-shared && make -j4
      
      - name: Run fuzzer (90 minutes)
        run: |
          mkdir -p seeds out
          echo "seed" > seeds/seed1
          timeout 5400 afl-fuzz -i seeds -o out -m none \
            -- ./target @@ || true
      
      - name: Check for crashes
        run: |
          if ls out/fuzzer01/crashes/id* 2>/dev/null; then
            echo "CRASHES FOUND"
            afl-whatsup out/
            exit 1
          fi
      
      - name: Upload findings
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: afl-findings
          path: out/
# Dockerfile for AFL++ fuzzing service on sota.io
FROM aflplusplus/aflplusplus:latest

WORKDIR /fuzz

COPY target-src/ ./src/
COPY seeds/ ./seeds/

RUN cd src && \
    CC=afl-clang-fast CXX=afl-clang-fast++ \
    CFLAGS="-fsanitize=address" \
    ./configure --disable-shared && make -j$(nproc)

CMD ["afl-fuzz", "-i", "seeds", "-o", "/out", "-m", "none", \
     "--", "./src/target", "@@"]

Regulatory Context: CRA 2027, NIS2, EU AI Act

CRA 2027 โ€” Cyber Resilience Act

The Cyber Resilience Act (effective September 2027) requires manufacturers of products with digital elements to:

AFL++ directly supports CRA compliance in two ways. First, continuous fuzzing of first-party code: running AFL++ on every pull request catches memory corruption, integer overflows, and assertion violations before they reach users. The afl-whatsup crash reports constitute machine-readable evidence of systematic security testing โ€” auditable for CRA conformance.

Second, fuzzing of third-party components: AFL++ nightly runs on dependencies (parsing libraries, compression codecs, network stacks) generate CVE-actionable findings. When a dependency is patched, the fuzz corpus documents that the fix was tested. This closes the supply-chain vulnerability loop that CRA Annex I explicitly targets.

NIS2 โ€” Article 21 (Cybersecurity Risk Management)

NIS2 Article 21 requires essential service operators to implement "appropriate and proportionate technical measures to manage the risks posed to the security of network and information systems." Fuzzing is the most cost-effective technique for finding the specific vulnerability classes (memory corruption, use-after-free, buffer overflows) that enable the denial-of-service and remote code execution attacks NIS2 is designed to prevent.

For operators of critical infrastructure implemented in C/C++ (industrial control systems, network routers, medical devices under MDR 2017/745), AFL++ provides a systematic, automatable risk reduction measure. The parallel fuzzing architecture (one AFL++ instance per core) scales to the compute available on a sota.io deployment without requiring dedicated hardware.

EU AI Act โ€” Article 9 (Risk Management System)

High-risk AI systems under EU AI Act Annex III include medical devices, biometric identification, critical infrastructure management, and educational systems. These systems are often implemented with C/C++ inference engines (TensorFlow Lite, ONNX Runtime, ncnn, MNN) that parse model files and process input tensors in memory.

AFL++ is applicable to:

EU AI Act Article 9(2)(e) requires "testing, evaluation, validation and verification of AI systems" โ€” AFL++ fuzzing reports constitute documented testing evidence for the Article 9 risk management system.

The CISPA Provenance: German Security Research Infrastructure

CISPA Helmholtz Center for Information Security was established in Saarbrรผcken, Germany in 2011 as part of the Helmholtz Association โ€” Germany's largest scientific organisation, named after physicist Hermann von Helmholtz. CISPA's budget comes from the German Federal Ministry of Education and Research (BMBF) and the State of Saarland. It has no US government funding, no US commercial affiliation, and no Cloud Act exposure.

CISPA's mandate explicitly includes "transferring research results into practical applications that strengthen IT security in Germany and Europe." AFL++ is the clearest example of this mandate fulfilled: a research-grade fuzzer that is now the default choice for open-source security hardening globally, maintained by researchers with EU institutional affiliation.

The AFL++ team:

Deploy AFL++ to EU Servers with sota.io

sota.io is the EU-native PaaS for deploying security testing infrastructure. Run AFL++ as a continuous fuzzing service โ€” always-on nightly campaigns across your entire codebase โ€” on European infrastructure, GDPR-compliant by default.

# sota.io deployment
sota deploy --image aflplusplus/aflplusplus:latest \
  --env AFL_TARGET=./target \
  --env AFL_SEEDS=/seeds \
  --region eu-west-1 \
  --persistent-volume /out

For EU organisations under NIS2 or CRA obligations, running AFL++ on EU-sovereign infrastructure ensures that the code being fuzzed โ€” which may include pre-release implementations of security-sensitive systems โ€” never leaves the EU regulatory perimeter. No Cloud Act. No cross-Atlantic transfer of security-sensitive source code or crash artefacts. No ambiguity about whether crash reports containing partial program state constitute personal data under GDPR Article 4.

The sota.io persistent volume stores the AFL++ corpus between runs, enabling incremental fuzzing campaigns: each nightly run builds on the corpus of the previous night, accumulating coverage rather than starting fresh. Managed PostgreSQL is available for storing crash metadata, coverage trends, and CVE-tracking across releases.

Apache 2.0 open source. Andrea Fioraldi ๐Ÿ‡ฎ๐Ÿ‡น (EURECOM ๐Ÿ‡ซ๐Ÿ‡ท โ†’ CISPA ๐Ÿ‡ฉ๐Ÿ‡ช). Dominik Maier ๐Ÿ‡ฉ๐Ÿ‡ช (TU Berlin โ†’ CISPA ๐Ÿ‡ฉ๐Ÿ‡ช). Heiko EiรŸfeldt ๐Ÿ‡ฉ๐Ÿ‡ช. Marc Heuse ๐Ÿ‡ฉ๐Ÿ‡ช. CISPA Helmholtz Center for Information Security, Saarbrรผcken ๐Ÿ‡ฉ๐Ÿ‡ช. github.com/AFLplusplus/AFLplusplus.