Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
seclab-taskflows-fuzzing — Un pipeline de fuzzing piloté par LLM propulsé par le GitHub Security Lab Taskflow Agent | Kitploit
Outils/GitHubGitHub/githubsecuritylab/seclab-taskflows-fuzzing
Analyse StatiqueScanners de VulnérabilitésAnalyse Dynamique (Sandboxing)Analyse des VulnérabilitésAnalyse de CodeScripting et AutomatisationFuzzingAnalyse de Malware
Utilitaires et Frameworks
Sécurité de l'IA
GitHubgithubsecuritylab/seclab-taskflows-fuzzing

seclab-taskflows-fuzzing

Un pipeline de fuzzing piloté par LLM propulsé par le GitHub Security Lab Taskflow Agent

Voir le dépôt
122il y a 4 joursPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Seclab Taskflows Fuzzing

Un pipeline de fuzzing de style OSS-Fuzz, piloté par LLM, pour les projets natifs C/C++. AFL++ pour l'exécution, clang+lcov pour la couverture, un agent LLM pour l'écriture de harness, les décisions basées sur les retours de couverture, le triage et le reporting.

  • Entièrement autonome : donnez-lui un dépôt GitHub et il gère tout, de l'identification de la cible aux rapports de vulnérabilité.
  • Techniques de style OSS-Fuzz : mutateurs/dictionnaires par format, épissage de tokens sensible à la structure, améliorations de harness guidées par la couverture.
  • Produit des rapports de crash lisibles par machine avec verdicts d'exploitabilité et correctifs suggérés.
  • Tableau de bord HTML en direct pour la surveillance des campagnes en temps réel.
  • Écrit en Python (taskflows/toolboxes/configs) avec génération de harness C pour AFL++.
  • Statut : Développement actif.

Contexte

Ce dépôt contient le taskflow de fuzzing pour le GitHub Security Lab Taskflow Agent. Il dépend du dépôt compagnon seclab-taskflows pour quelques blocs de construction partagés (taskflow fetch_source_code, toolboxes local_file_viewer / gh_file_viewer, et le model_config par défaut) — ceux-ci sont installés automatiquement en tant que dépendance Python.

Les contributions sont les bienvenues ! Veuillez consulter CONTRIBUTING.md pour les directives.

Prérequis

  • Python 3.11+
  • Un environnement Linux (ou Codespace) avec accès à apt
  • AFL++, clang, lcov, ctags, cscope, graphviz (auto-installés par le pipeline s'ils sont manquants)
  • Git et GitHub CLI (gh)

Installation```bash

pip install git+https://github.com/GitHubSecurityLab/seclab-taskflows-fuzzing

root@kitploit:~
Cela intègre `seclab-taskflow-agent` et `seclab-taskflows` (parent)
de manière transitive, de sorte que chaque référence pointée de la forme
`seclab_taskflows.taskflows.audit.*`,
`seclab_taskflows.toolboxes.local_file_viewer`,
`seclab_taskflows.toolboxes.gh_file_viewer`, et
`seclab_taskflows.configs.model_config` se résout à partir de la distribution
parente à l'exécution.

---

## Table des matières

1. [Ce que c'est](#what-this-is)
2. [Démarrage rapide](#quick-start)
3. [Architecture](#architecture)
4. [Le pipeline, étape par étape](#the-pipeline-stage-by-stage)
5. [La boucle de rétroaction de couverture](#the-coverage-feedback-loop)
6. [Fuzzing sensible à la structure](#structure-aware-fuzzing)
7. [Corpus persistant à travers les itérations et les campagnes](#persistent-corpus-across-iterations-and-campaigns)
8. [Triage et rapports de vulnérabilité](#triage-and-vulnerability-reports)
9. [Tableau de bord en direct](#live-dashboard)
10. [Fichiers de sortie](#output-files)
11. [Schéma de base de données](#database-schema)
12. [Outils MCP (le vocabulaire de l'agent)](#mcp-tools-the-agents-vocabulary)
13. [Paramètres ajustables (variables d'environnement)](#tunable-knobs-environment-variables)
14. [Étendre le pipeline](#extending-the-pipeline)
15. [Projets de référence et résultats](#benchmark-projects-and-results)
16. [Limitations et pièges](#limitations-and-gotchas)
17. [Avertissement de sécurité](#security-warning)
18. [Développement : tests, linting, contribution](#development-testing-linting-contributing)
19. [Glossaire](#glossary)

---

## Ce que c'est

Ce taskflow est un pipeline de fuzzing entièrement autonome. Étant donné un dépôt GitHub
d'un projet natif C/C++, il va :

1. installer AFL++ + clang/llvm/lcov + ctags/cscope/graphviz s'ils sont absents,
2. récupérer le code source,
3. identifier les cibles de fuzzing candidates (parseurs, décodeurs, validateurs, …),
4. analyser le système de build,
5. écrire un ou plusieurs candidats de harnais par cible, compiler chacun à la fois comme un
   binaire `.afl` instrumenté par AFL et un binaire `.cov` instrumenté pour la couverture,
6. (optionnellement) qualifier les candidats par une couverture de 60 secondes et garder le meilleur,
7. exécuter une boucle fuzz/couverture/amélioration avec des budgets de temps doublés,
8. trier chaque crash, confirmer que les crashes précédemment connus se reproduisent toujours, et
   écrire des rapports de vulnérabilité markdown par crash avec des verdicts, l'exploitabilité,
   des correctifs suggérés, et des esquisses de tests de régression,
9. construire un graphe d'appels de style Fuzz-Introspector + un rapport d'API non touchée pour la
   campagne suivante,
10. publier le tout sur un tableau de bord HTML en direct.

Le pipeline est **de style OSS-Fuzz** dans l'esprit : il utilise un grand nombre des mêmes
techniques (mutateurs et dictionnaires par format, épissage de tokens sensible à la structure,
améliorations de harnais guidées par la couverture, rapports lisibles par machine,
crashes dédupliqués par hachage de pile) mais il est beaucoup plus petit et autonome.

---

## Démarrage rapide```bash
# Inside the codespace (or a host with python + git available):
./scripts/fuzzing/run_fuzzing.sh tukaani-project/xz

C'est toute l'interface. Le script est autonome ; il installera AFL++ lors de la première exécution, puis pilotera le reste du flux de tâches. Les fichiers de sortie sont écrits dans ~/.local/share/seclab-taskflow-agent/seclab-taskflows/.

Le tableau de bord démarre automatiquement en arrière-plan ; dans un Codespace, le port 8765 est automatiquement redirigé — ouvrez-le dans n'importe quel navigateur pour suivre la progression en direct.

Pour un test rapide, utilisez une petite cible :```bash ./scripts/fuzzing/run_fuzzing.sh DaveGamble/cJSON

root@kitploit:~
## Architecture

Trois couches, de haut en bas :```
┌────────────────────────────────────────────────────────────────────┐
│  scripts/fuzzing/run_fuzzing.sh                                    │
│      shell driver; chains the taskflow stages with `set +e`        │
└────────────────────┬───────────────────────────────────────────────┘
                     │
                     ▼
┌────────────────────────────────────────────────────────────────────┐
│  src/seclab_taskflows/taskflows/fuzzing/*.yaml                     │
│      LLM agent prompts; one YAML per pipeline stage                │
└────────────────────┬───────────────────────────────────────────────┘
                     │  (calls MCP tools)
                     ▼
┌────────────────────────────────────────────────────────────────────┐
│  src/seclab_taskflows/mcp_servers/                                 │
│   ├ fuzz_context.py    persistence (SQLite via SQLAlchemy)         │
│   └ fuzz_runner.py     subprocess wrappers (AFL, clang, lcov, ...) │
│                                                                    │
│  scripts/fuzzing/dashboard.py                                      │
│   read-only HTML view of fuzz_context.db                           │
└────────────────────────────────────────────────────────────────────┘

Règles de conception clés :

  • Aucun état global dans les outils MCP. Chaque fonction d'outil prend des arguments explicites ; l'état persistant réside dans fuzz_context.db.
  • Les agents LLM possèdent les décisions, les outils MCP possèdent l'exécution. L'agent décide quoi fuzzer, quel harness écrire, quel écart poursuivre ensuite ; les outils MCP exposent simplement run_afl_for, compile_harness, store_crash, etc.
  • Idempotence partout où c'est peu coûteux. Réexécuter le pipeline sur le même dépôt fait un upsert des cibles/harnesses/exécutions plutôt que de les dupliquer. C'est ce qui fait fonctionner le corpus persistant et la reprise entre campagnes.
  • Deux binaires par harness. L'instrumentation par arêtes d'AFL est inadaptée aux rapports de couverture lisibles par l'humain, donc chaque harness est compilé deux fois : une fois avec afl-clang-lto -fsanitize=address,undefined (le binaire .afl) et une fois avec clang -fprofile-instr-generate -fcoverage-mapping (le binaire .cov). Le binaire .afl fuzze ; le binaire .cov rejoue la file d'attente AFL pour produire une couverture réelle des lignes source/fonctions/branches.

Le pipeline, étape par étape

#ÉtapeTaskflow YAML
1Installer AFL++ + outillagescripts/fuzzing/install_afl.sh
2Récupérer les sourcesseclab_taskflows.taskflows.audit.fetch_source_code
3Identifier les cibles de fuzzingseclab_taskflows_fuzzing.taskflows.fuzzing.identify_fuzz_targets
4Analyser le système de buildseclab_taskflows_fuzzing.taskflows.fuzzing.analyze_build_system
5aÉcrire les harnesses initiaux (×N candidats si demandé)seclab_taskflows_fuzzing.taskflows.fuzzing.write_initial_harnesses
5bCompiler les harnesses (AFL + couverture)seclab_taskflows_fuzzing.taskflows.fuzzing.build_harnesses
5cQualifier les candidats (quand HARNESS_CANDIDATES > 1)seclab_taskflows_fuzzing.taskflows.fuzzing.qualify_harnesses
6Boucle fuzzing/couverture/amélioration (×N itérations)seclab_taskflows_fuzzing.taskflows.fuzzing.fuzz_iteration
7Trier les crashesseclab_taskflows_fuzzing.taskflows.fuzzing.triage_crashes
8Confirmer que les crashes précédemment connus se reproduisent toujoursseclab_taskflows_fuzzing.taskflows.fuzzing.confirm_fixed_crashes
9Construire le graphe d'appels + rapport des API non touchéesseclab_taskflows_fuzzing.taskflows.fuzzing.analyze_call_graph
10Écrire les rapports de vulnérabilité par crashseclab_taskflows_fuzzing.taskflows.fuzzing.write_vuln_reports
11Écrire le rapport de campagneseclab_taskflows_fuzzing.taskflows.fuzzing.write_report

Chaque étape est un taskflow YAML autonome que l'agent exécute de bout en bout. Les étapes communiquent exclusivement via la base de données SQLite dans fuzz_context.db — il n'y a aucun transfert en mémoire.


La boucle de rétroaction de couverture

C'est le cœur du pipeline. Les budgets de temps doublent à chaque itération :``` 30s → 60s → 120s → 240s → 480s → 960s (≈ 32 min/target)

root@kitploit:~
À chaque itération, pour chaque harness, l'agent :

1. Demande `get_persistent_corpus_dir(harness_id)` pour obtenir le répertoire
   de corpus stable de ce harness.
2. Appelle `run_afl_for(afl_binary_path, seed_dir=<persistent corpus>,
   output_dir=<run dir>, seconds=<budget>, dictionary=<auto.dict>)`.
3. Appelle `run_coverage(cov_binary_path, inputs_dir=<run>/default/queue,
   output_dir=<run>/coverage)` pour produire un fichier de trace LCOV et un rapport HTML.
4. Appelle `store_coverage_from_lcov(run_id, lcov_path, html_path)` pour persister
   une ligne `coverage_report` + des lignes `coverage_gap` par élément non couvert.
5. Appelle `fold_queue_into_persistent_corpus(...)` pour fusionner la file d'attente
   d'itération d'AFL dans le corpus persistant et exécuter `cmin` pour maintenir la taille bornée.
6. Lit `get_coverage_summary` + `get_coverage_gaps`, puis soit :
   - ajoute une nouvelle graine (étiquetée `coverage_feedback`) pour atteindre une
     branche non couverte,
   - modifie la source du harness pour appeler une API supplémentaire,
   - appelle `enrich_dictionary_from_uncovered(...)` pour ajouter automatiquement des entrées
     de dictionnaire pour les constantes magiques dont AFL a besoin pour satisfaire une garde, ou
   - ignore la lacune (chemin d'erreur froid / code fournisseur).
7. Appelle `store_iteration_note(repo, iteration_number, harness_id, note=<résumé
   en une ligne>)` afin que la chronologie des itérations du tableau de bord suive ce qui
   a changé.

**Détection de plateau.** La boucle se termine prématurément dès que deux itérations consécutives
ont toutes deux gagné < `FUZZ_PLATEAU_THRESHOLD_PCT` (par défaut `1.0`) points de pourcentage
absolus de couverture de lignes.

---

## Fuzzing conscient de la structure

Trois mécanismes complémentaires produisent des entrées plus fortes que la mutation brute d'octets.

### 1. Dictionnaires par format + mutateurs personnalisés

Pour les cibles dont `input_kind` correspond à un format connu, le taskflow fournit
des dictionnaires préconstruits et des fichiers source C `LLVMFuzzerCustomMutator` :

| Format | Dictionnaire | Mutateur | Notes |
|--------|------------|---------|-------|
| `json` | `json.dict` | `json_mutator.c` | Épissage de tokens, duplication/suppression de crochets équilibrés, inversion de type |
| `xml` | `xml.dict` | `xml_mutator.c` | Balises, entités, DTD, tokens billion-laughs |
| `regex` | `regex.dict` | `regex_mutator.c` | Ancres, classes, quantificateurs, motifs ReDoS réels |
| `binary_tlv` | _(aucun)_ | `binary_tlv_mutator.c` | Enregistrements préfixés par longueur : dépassement de longueur / duplication / suppression |
| `png` | `png.dict` | _(réutilise binary_tlv)_ | Dictionnaire PNG + mutateur binary_tlv |

Ceux-ci sont récupérés automatiquement par `write_initial_harnesses` (dictionnaire
copié à côté des graines) et `build_harnesses` (mutateur lié dans le binaire
AFL). Chaque mutateur délègue 50 % des mutations au mutateur d'octets par défaut d'AFL
afin de ne pas perdre la randomisation du moteur.

Pour ajouter un nouveau format : déposez un `<name>.dict` et/ou un `<name>_mutator.c` dans
`src/seclab_taskflows/dictionaries/`, puis enregistrez-le dans la
map `_FORMAT_ASSETS` en bas de `fuzz_runner.py`.

### 2. Mutateur intelligent conscient de la source (spécifique au projet)

Pour les formats inconnus, ou chaque fois que vous voulez des tokens plus forts
spécifiques au projet, `generate_smart_mutator` analyse les propres fichiers `.c`/`.h`
du dépôt cible et émet un fichier C `LLVMFuzzerCustomMutator` dont les dictionnaires
d'épissage sont extraits de :

- littéraux de chaîne avec ≥3 caractères alphabétiques (après filtrage du bruit
  du compilateur/licence, des chemins, des en-têtes, des contraintes asm, des spécificateurs de format),
- constantes numériques 32 bits issues de `#define`, `case` et `enum` (après
  filtrage du bruit générique de petits entiers comme 0, 1, 256, 0xff…).

Trois focus sont disponibles :

| Focus | Ce qu'il épisse | Quand l'utiliser |
|-------|-----------------|-------------|
| `strings` | Littéraux de chaîne du projet uniquement | Formats texte (JSON, XML, YAML, CSV) |
| `constants` | Valeurs magiques numériques 32 bits uniquement | Protocoles binaires, en-têtes avec nombres magiques |
| `combined` | Les deux | Par défaut ; généralement le meilleur |

Associez `generate_smart_mutators(...)` (au pluriel) avec `HARNESS_CANDIDATES >= 3`
afin que chaque focus devienne un harness candidat lors du tour de qualification.

### 3. Dictionnaire AFL conscient du projet + enrichissement piloté par la couverture

Deux outils complémentaires construisent et développent un dictionnaire AFL `-x` au
fur et à mesure de la campagne :

- **`generate_project_dictionary(source_root, output_path)`** — s'exécute une fois
  avant l'itération 1, extrait statiquement le même ensemble de tokens source que
  celui utilisé par le mutateur intelligent et l'écrit sous forme de dictionnaire AFL. Les constantes
  numériques sont émises dans LES DEUX endianness afin que le fuzzer puisse satisfaire
  `memcmp(x, &magic, 4)` quel que soit l'ordre des octets de l'hôte.

- **`enrich_dictionary_from_uncovered(source_root, dictionary_path,
  uncovered_locations)`** — s'exécute après l'étape de couverture de chaque itération,
  analyse la source environnante pour les gardes conditionnelles
  (`strncmp/memcmp/strstr`, `case 0xN:`, `== 0xN`, `== 'X'`) à proximité des
  lignes non couvertes, et AJOUTE tous les nouveaux tokens au dictionnaire. Idempotent :
  ne rajoute jamais une entrée déjà présente.

### 4. Opération d'épissage de corpus

Lorsque `corpus_dir` est passé à `generate_smart_mutator`, le C généré
reçoit également un opérateur d'épissage de corpus : au premier appel, il charge jusqu'à 64 fichiers
depuis ce répertoire (plafonnés à 4 Kio chacun), et à partir de là peut épisser
des sous-régions aléatoires de ces fichiers dans l'entrée mutée. Cela donne au
mutateur un opérateur de style recombinaison que le havoc standard d'AFL ne fait pas
bien. Associez-le à `get_persistent_corpus_dir(...)` afin que la bibliothèque d'épissage
soit « remixez ce qu'AFL a déjà découvert ».

---

## Corpus persistant à travers les itérations et les campagnes

Chaque harness dispose d'un répertoire de corpus stable à l'emplacement :```
<workspace>/corpus/harness_<id>/

Voici ce que fuzz_iteration utilise comme seed_dir pour run_afl_for (plutôt que <harness>/seeds). À la fin de chaque itération, fold_queue_into_persistent_corpus(...) fusionne la file d'attente d'itération d'AFL dans ce répertoire et exécute afl-cmin pour la maintenir bornée.

Le résultat : la file d'attente d'hier est reportée dans l'exécution d'aujourd'hui ET à travers les ré-exécutions du même projet. Un arrêt-redémarrage de la campagne ne perd aucun progrès.


Triage et rapports de vulnérabilité

Une fois la boucle fuzz/couverture/amélioration terminée, trois étapes s'exécutent automatiquement :

1. triage_crashes

Pour chaque fichier de crash dans <run>/default/crashes/ :

  • afl-tmin pour minimiser l'entrée,
  • replay_under_asan pour capturer une trace de pile et stack_top_hash (top-N frames normalisées ; les templates, les espaces de noms inline de libcxx, les espaces de noms anonymes et les suffixes numériques LTO sont supprimés afin que des crashes sémantiquement identiques produisent le même hash),
  • déduplication par hash, persistance d'une ligne crash avec classification de classe de bug + note de confiance (élevée / moyenne / faible).

2. confirm_fixed_crashes

Rejoue chaque crash précédemment classifié (dont le verdict n'est pas déjà fixed/duplicate/non_reproducible) à travers le binaire AFL+ASan actuel. S'il ne plante plus, marque verdict="fixed". Utile lors de la ré-exécution d'une campagne contre un projet ayant reçu des correctifs en amont depuis la dernière campagne.

3. write_vuln_reports

Pour chaque crash unique, l'agent lit la source du harness + la source de la fonction qui plante, parcourt la chaîne d'appels depuis l'API publique, puis attribue l'un des dix verdicts de style OSS-Fuzz et écrit un rapport de vulnérabilité markdown :

VerdictSignification
vulnerabilityRéel, exploitable via une API publique
library_hardeningBug réel mais aucun chemin réaliste via l'API publique ; la bibliothèque devrait tout de même se défendre
harness_bugLe bug est dans notre harness, pas dans la bibliothèque
non_reproducibleLe replay ne reproduit pas le crash sur l'entrée minimisée
oomOut-of-memory ; vulnérabilité uniquement si la taille contrôlable par l'attaquant est non bornée
timeoutDoS via explosion algorithmique
assertion_failureassert() déclenché ; pertinence de sécurité variable
fixedDéfini par confirm_fixed_crashes : l'entrée ne reproduit plus le crash
duplicateMême cause racine qu'un autre crash avec un hash de pile différent
needs_investigationImpossible à déterminer ; signalé pour revue humaine

Chaque rapport de vulnérabilité inclut :

  • Verdict + classe de bug + CWE + sévérité + confiance
  • Analyse de la cause racine avec références fichier:ligne
  • Atteignabilité depuis l'API publique (chaîne d'appels concrète)
  • Évaluation de l'exploitabilité (lecture vs. écriture, contrôle de l'attaquant, mitigations)
  • Correctif suggéré sous forme de diff unifié (marqué « review required »)
  • Esquisse de test de régression

Tableau de bord en direct

Le tableau de bord est démarré automatiquement en arrière-plan par run_fuzzing.sh. Désactivez-le avec FUZZ_NO_DASHBOARD=1 ; remplacez le port avec FUZZ_DASHBOARD_PORT (par défaut 8765).

Dans un Codespace, le port 8765 est automatiquement redirigé — ouvrez l'URL redirigée dans n'importe quel navigateur. La page s'actualise automatiquement toutes les 5 s et affiche :

  • Puces de résumé des verdicts — comptages par catégorie de verdict, exécutions totales, chemins, nombre total d'exécutions, crashes
  • Indicateur de pulsation « running » en direct — par dépôt et par harness avec un fuzz_run en cours
  • Tableau de tendance de couverture avec sparklines SVG en ligne et une colonne de delta par itération
  • Graphe d'appels et surface d'API non touchée — l'instantané Fuzz-Introspector-lite
  • Tableau des crashes — trié par verdict (vulnerability en premier), avec liens vers chaque rapport de vulnérabilité et entrée minimisée
  • Carte thermique des crashes — grille par-(harness × itération) des comptages de crashes, l'opacité évolue avec le comptage
  • Chronologie des itérations — flux chronologique de notes d'une ligne écrites par l'agent décrivant ce qui a changé à chaque itération
  • Fonctions non couvertes principales — repliées par défaut

API JSON

Le tableau de bord expose également une petite API JSON en lecture seule pour les scripts :```bash

All known repos

curl http://127.0.0.1:8765/api/json

Per-repo: harnesses, per-iteration coverage, crashes with verdicts

curl 'http://127.0.0.1:8765/api/json?repo=kkos/oniguruma' | jq .

root@kitploit:~
---

## Fichiers de sortie

Tous sous `~/.local/share/seclab-taskflow-agent/seclab-taskflows/`.

| Chemin | Contenu |
|------|----------|
| `fuzz_context/fuzz_context.db` | SQLite — cibles, harnesses, exécutions, couverture, crashes, verdicts, graphes d'appels, suggestions de harness, notes d'itération |
| `fuzz_runner/builds/` | Binaires `.afl` et `.cov` compilés |
| `fuzz_runner/runs/` | Répertoires de sortie AFL + fichiers LCOV + rapports de couverture HTML |
| `fuzz_runner/corpus/harness_<id>/` | Corpus persistant par harness (conservé entre les itérations et les campagnes) |
| `fuzz_runner/repo/<owner>__<repo>/REPORT.md` | Résumé de campagne Markdown, crashes groupés par verdict |
| `fuzz_runner/repo/<owner>__<repo>/vuln_<crash_id>.md` | Rapport de vulnérabilité Markdown par crash |
| `fuzz_runner/repo/<owner>__<repo>/call_graph.{dot,svg,md}` | Graphe d'appels statique + superposition atteint/non atteint |

---

## Schéma de la base de données

Tables dans `fuzz_context.db` (SQLite via SQLAlchemy) :

| Table | Colonnes d'intérêt |
|-------|--------------------|
| `fuzz_target` | `repo, file, function, signature, input_kind` |
| `harness` | `target_id, repo, harness_path, afl_binary_path, cov_binary_path, build_status, version, sanitizers` |
| `seed_corpus` | `target_id, source, path, bytes_count, added_in_iteration` |
| `fuzz_run` | `harness_id, iteration_number, exec_per_sec, paths_total, crashes_count, status, output_dir, started_at, ended_at` |
| `coverage_report` | `run_id, lines_total, lines_hit, line_pct, fns_*, branches_*, lcov_path, html_path` |
| `coverage_gap` | `report_id, file, function, line, kind, reason_hint` |
| `crash` | `run_id, input_blob_path, minimized_path, stack_top_hash, sanitizer_output, verdict, bug_class, cwe, severity, vuln_report_path, reproducer_path, classification, notes` |
| `call_graph` | `repo, target_id, dot_path, svg_path, functions_total, functions_in_graph, functions_reached, functions_unreached, untouched_surface_json` |
| `harness_suggestion` | `repo, function_name, file, rationale, input_kind, priority` |
| `iteration_note` | `repo, harness_id, iteration_number, note, created_at` |

Les migrations de schéma se trouvent dans `_migrate()` dans `fuzz_context.py`. Les nouvelles TABLES sont
créées automatiquement par `Base.metadata.create_all()` ; seules les nouvelles COLONNES nécessitent
un `ALTER TABLE` basé sur PRAGMA.

---

## Outils MCP (le vocabulaire de l'agent)

L'agent n'appelle jamais AFL ou clang directement — il compose le pipeline en
appelant des outils MCP. L'ensemble complet, groupé par objectif :

### Persistance (`fuzz_context.py`)

- `store_fuzz_target`, `get_fuzz_targets`
- `store_harness`, `update_harness_build`, `get_harnesses`
- `store_seed`, `start_fuzz_run`, `finish_fuzz_run`, `get_fuzz_runs`
- `store_coverage_from_lcov`, `get_coverage_summary`, `get_coverage_gaps`,
  `coverage_plateau_reached`
- `store_crash`, `update_crash_verdict`, `get_crashes`,
  `get_crashes_grouped`, `suggest_severity`
- `store_call_graph`, `get_call_graphs`, `get_repo_reached_functions`
- `store_harness_suggestion`, `get_harness_suggestions`
- `store_iteration_note`, `get_iteration_notes`

### Build / fuzz / couverture (`fuzz_runner.py`)

- `check_tooling`, `workspace_paths`
- `compile_harness` — compile les binaires `.afl` et `.cov`
- `run_afl_for`, `cmin`, `tmin`, `replay_under_asan`, `reproduce_crash`
- `run_coverage` — rejoue la file d'attente AFL contre le binaire `.cov`, exporte LCOV
- `extract_dictionary` — extrait les chaînes imprimables d'un binaire
- `package_reproducer` — regroupe un `.tgz` pour un crash unique

### Corpus persistant (v8)

- `get_persistent_corpus_dir`, `fold_queue_into_persistent_corpus`

### Ressources de format (C5)

- `list_format_assets`, `get_format_dictionary`, `write_format_mutator`

### Mutateur intelligent + dictionnaire conscient du projet

- `generate_smart_mutator`, `generate_smart_mutators`
- `generate_project_dictionary`, `enrich_dictionary_from_uncovered`

Les fonctions d'outil sont décorées avec `@mcp.tool()` (FastMCP). Dans les tests,
invoquez-les via l'attribut `.fn`, par ex.
`fr.run_afl_for.fn(afl_binary_path=..., ...)`.

---

## Paramètres ajustables (variables d'environnement)

| Variable | Défaut | Objectif |
|----------|---------|---------|
| `HARNESS_CANDIDATES` | `1` | Nombre de harnesses candidats écrits par cible. Définir à 2 ou 3 pour une compétition de style OSS-Fuzz-Gen. L'étape de qualification exécute chacun pendant `QUALIFIER_SECONDS` et conserve le meilleur selon le % de lignes. |
| `QUALIFIER_SECONDS` | `60` | Budget en temps réel par candidat dans l'étape de qualification. |
| `FUZZ_PLATEAU_THRESHOLD_PCT` | `1.0` | Gain de couverture de lignes (en pp absolus) en dessous duquel deux itérations consécutives sont considérées comme un plateau et la boucle s'arrête prématurément. |
| `FUZZ_DASHBOARD_PORT` | `8765` | Port pour le tableau de bord en direct. |
| `FUZZ_NO_DASHBOARD` | (non défini) | Définir à `1` pour ignorer le démarrage du tableau de bord. |
| `FUZZ_RUNNER_TIMEOUT` | `1200` | Délai d'expiration du sous-processus par outil dans `fuzz_runner` (secondes). |
| `LOCAL_SHELL_TIMEOUT` | `180` | Délai d'expiration par commande dans `local_shell` (secondes). |

Plus les variables d'agent standard (`COPILOT_TOKEN`, `LOG_DIR`,
`FUZZ_CONTEXT_DIR`, …). Voir le README à la racine du projet pour la liste complète.

---

## Étendre le pipeline

### Ajouter un nouveau format (mutateur + dictionnaire)

1. Déposez `dictionaries/<name>.dict` (format AFL `-x`) et/ou
   `dictionaries/<name>_mutator.c` (mutateur personnalisé libFuzzer).
2. Enregistrez dans `_FORMAT_ASSETS` en bas de `fuzz_runner.py` :   ```python
   "<name>": {
       "dictionary": "<name>.dict",
       "mutator": "<name>_mutator.c",
       "description": "Short one-liner about the format",
   },
  1. L'agent le récupérera automatiquement via list_format_assets().

Ajouter un nouvel outil MCP

  1. Ajoutez une fonction décorée avec @mcp.tool() dans fuzz_context.py (pour la persistance) ou fuzz_runner.py (pour le travail en sous-processus).
  2. Utilisez Annotated[type, Field(description=...)] pour chaque argument — la description est ce que le LLM voit.
  3. Ajoutez un test unitaire dans tests/test_fuzz_context.py / tests/test_fuzz_runner.py. Invoquez l'outil via son attribut .fn (convention FastMCP).
  4. Référencez le nouvel outil dans le user_prompt du YAML de taskflow concerné.

Ajouter une nouvelle étape de pipeline

  1. Créez un nouveau YAML dans src/seclab_taskflows/taskflows/fuzzing/. Utilisez l'un des fichiers existants (par ex. triage_crashes.yaml) comme modèle.
  2. Câblez-le dans scripts/fuzzing/run_fuzzing.sh entre les deux bonnes étapes existantes.
  3. (Optionnel) ajoutez une section de tableau de bord spécifique à l'étape dans scripts/fuzzing/dashboard.py.

Migration de schéma

Lors de l'ajout d'une nouvelle table SQL :

  • Ajoutez le modèle SQLAlchemy dans fuzz_context_models.py.
  • Rien d'autre n'est nécessaire — Base.metadata.create_all() est appelé à l'initialisation du moteur et crée automatiquement les nouvelles tables.

Lors de l'ajout d'une nouvelle COLONNE à une table existante :

  • Mettez à jour le modèle SQLAlchemy.
  • Ajoutez un bloc PRAGMA table_info + ALTER TABLE ADD COLUMN dans _migrate() dans fuzz_context.py afin que les anciennes bases de données soient mises à niveau de manière transparente.
  • Si la colonne est lue par le tableau de bord, mettez également à jour _migrate_if_writable() dans scripts/fuzzing/dashboard.py.

Projets de référence et résultats

benchmark/projects.yaml liste les projets de référence. Ils sont choisis pour que le pipeline complet v4+ puisse s'exécuter de bout en bout sur une image de développement codespace sans intervention humaine.

#DépôtPourquoi il est intéressantNotes
1tukaani-project/xzBibliothèque réelle à forte composante d'analyse syntaxique (liblzma) ; chaîne de filtres riche + surface d'analyse d'entiers/VLIRéférence
2DaveGamble/cJSONPetit analyseur JSON C en un seul fichier ; CMake trivialTest rapide pour le pipeline
3akheron/janssonBibliothèque JSON C compacte avec un point d'entrée documenté json_loadb() sur tampon d'octetsCMake ; exec/sec très rapide
4libexpat/libexpatAnalyseur XML en flux mature ; nombreux CVE historiquesCMake ou autotools
5kkos/onigurumaMoteur de regex ; prend un motif et un sujet contrôlés par l'attaquantAutotools ; la compilation du motif est le chemin critique

Chiffres de référence d'une exécution complète du pipeline v4 sur l'image de développement codespace (≈32 min/cible) :

DépôtCiblesHarnaisExécutions AFLCrashsVerdicts
tukaani-project/xz88480—
DaveGamble/cJSON66360—
akheron/jansson773510harness_bug, library_hardening, duplicate, needs_investigation
libexpat/libexpat33180—
kkos/oniguruma10106013vulnerability (×2 lecture hors limites dans regerror.c), library_hardening, harness_bug, non_reproducible

Les résultats sans crash de xz / cJSON / libexpat sont attendus : ces projets sont massivement fuzzés en amont. Les deux constats classés vulnerability dans oniguruma sont de véritables lectures hors limites dans le chemin de code de formatage des avertissements de onig_snprintf_with_pattern (lecture d'un octet au-delà de pat_end lorsque le motif se termine par une barre oblique inverse) ; les rapports markdown par crash incluent des correctifs suggérés.

Pour ajouter un nouveau projet de référence, ajoutez une entrée dans benchmark/projects.yaml et (éventuellement) documentez la raison dans benchmark/README.md. Tout ce que l'étape existante analyze_build_system peut compiler avec clang + les drapeaux AFL++ est un candidat raisonnable. Les analyseurs, décodeurs et sérialiseurs en C pur ont tendance à mieux fonctionner.


Limitations et pièges

  • C / C++ uniquement. AFL++ est un fuzzer à instrumentation native.
  • Dépendant du système de build. Les projets avec des systèmes de build non triviaux (règles Bazel personnalisées, libc embarquée, outils de build propriétaires) peuvent échouer à se compiler avec les drapeaux clang/AFL. L'agent marque ces cibles BUILD_FAILED: et les ignore.
  • Avertissements AFL dans Codespace. AFL++ veut kernel.core_pattern=core et un ajustement du governor CPU. Dans un Codespace, ceux-ci sont indisponibles, donc le taskflow exporte AFL_SKIP_CPUFREQ=1 et AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 par défaut. AFL affiche des avertissements mais trouve quand même des crashs via la gestion des abandons de type libFuzzer.
  • Limité par le modèle. La qualité de rédaction des harnais par l'agent est limitée par la compréhension du code cible par le modèle sous-jacent.
  • Splice de corpus du mutateur intelligent POSIX uniquement. L'opération de splice de corpus utilise <dirent.h>. Correct pour Linux/macOS ; ne se compilerait pas sous Windows.
  • Mise en garde sur le mode stdin. Les binaires AFL compilés via compile_harness utilisent libAFLDriver en mode argv. replay_under_asan et tmin utilisent donc par défaut stdin_input=False car libAFLDriver boucle indéfiniment lorsqu'il est piloté via stdin.
  • generate_smart_mutator + generate_smart_mutators utilisent le .format() de Python — chaque { / } littéral dans le template C doit être doublé ({{ / }}). Si vous modifiez le template et commencez à voir des KeyError, c'est la raison.

Avertissement de sécurité

Ce taskflow exécute afl-fuzz, clang, llvm-cov, et des commandes de build arbitraires choisies par le LLM, directement sur l'hôte (sans conteneur). Un agent soumis à une injection de prompt pourrait en principe faire tout ce que votre utilisateur peut faire. Exécutez-le uniquement :

  • dans des environnements jetables (GitHub Codespaces, VM éphémères, etc.),
  • sans privilèges élevés,
  • avec un accès réseau limité à ce dont git, apt et le système de build ont besoin.

La boîte à outils local_shell n'est PAS derrière une invite de confirmation — le taskflow est autonome et s'exécute sans humain dans la boucle, donc une confirmation interactive bloquerait indéfiniment. Chaque commande shell est journalisée dans $LOG_DIR/mcp_local_shell.log pour un examen a posteriori.


Développement : tests, linting, contribution```bash

Run the test suite (Python 3.11+ required by hatch-test envs)

hatch test

Run the linter

hatch fmt --linter --check

Auto-fix lint issues

hatch fmt --linter

Lint a single file

hatch fmt --linter --check -- src/seclab_taskflows/mcp_servers/fuzz_runner.py

root@kitploit:~
Conventions de base de code (voir aussi `benchmark/improvements.md` pour la version historique de campagne de celles-ci) :

- Utilisez `os.environ.get(NAME) or "default"` plutôt que
  `os.environ.get(NAME, "default")`. Les chaînes vides issues de la substitution
  de template YAML seraient sinon retournées.
- Utilisez `X | None` (PEP 604) dans les nouvelles annotations, pas `Optional[X]`.
- Les tests invoquent les outils MCP via `.fn(...)`, pas le nom décoré directement.
- Évitez les littéraux `/tmp/...` dans les tests — utilisez la fixture pytest `tmp_path`
  (règle de lint `S108`).
- Tous les imports en ligne à l'intérieur des méthodes de test nécessitent `# noqa: PLC0415` si vous
  ne pouvez pas les déplacer en haut du fichier (par exemple lorsqu'ils sont importés conditionnellement
  après un `pytest.skip`).
- Une seule assertion par ligne pour les tests de vérité composés (règle de lint `PT018`).

Le suivi des améliorations (`benchmark/improvements.md`) est le journal persistant
de ce qui a été ajouté au pipeline au fil des versions. Lorsque vous ajoutez une
fonctionnalité substantielle, ajoutez-y une section décrivant ce qui a changé, où cela
se trouve, et quels tests le protègent.

---

## Glossaire

- **AFL++** — Fuzzer greybox guidé par la couverture ; le moteur d'exécution ici.
- **libAFLDriver** — Bibliothèque statique qui permet aux harnais AFL++ d'utiliser
  la convention de point d'entrée libFuzzer (`LLVMFuzzerTestOneInput`).
- **LCOV** — Format de fichier de trace de couverture standard de l'industrie. Nous exportons vers celui-ci
  via `llvm-cov export -format=lcov` et le parsons nous-mêmes.
- **`stack_top_hash`** — Un hash de 16 caractères des N premières trames normalisées d'une
  trace de pile ASan/UBSan. Utilisé pour la déduplication des crashs.
- **Corpus persistant** — Répertoire par harnais à
  `<workspace>/corpus/harness_<id>/` qui conserve les entrées intéressantes d'AFL
  à travers les itérations et les ré-exécutions d'une même campagne.
- **Mutateur intelligent** — Un `LLVMFuzzerCustomMutator` dont les jetons de splice sont
  extraits du propre code source de la cible (`generate_smart_mutator`).
- **Mutateur personnalisé (libFuzzer)** — Une fonction C fournie par l'utilisateur appelée par
  le moteur avec une liberté totale sur la façon de muter un buffer ; AFL++ prend en charge
  la même ABI.
- **Outil MCP** — Une fonction décorée par FastMCP que l'agent LLM peut appeler.
- **OSS-Fuzz / Fuzz-Introspector** — L'infrastructure de fuzzing open-source de Google
  et son outil compagnon d'analyse de graphe d'appels/couverture.
  Plusieurs fonctionnalités de ce taskflow (mutateurs par format, déduplication par pile,
  rapport de graphe d'appels + API non touchées, harnais multi-candidats) sont
  inspirées par ceux-ci.

---

## Licence

Ce projet est sous licence selon les termes de la licence open source MIT. Veuillez vous référer au fichier [LICENSE](https://github.com/githubsecuritylab/seclab-taskflows-fuzzing/blob/main/LICENSE.txt) pour les termes complets.

## Mainteneurs

Voir [CODEOWNERS](https://github.com/githubsecuritylab/seclab-taskflows-fuzzing/blob/main/CODEOWNERS) ou contactez l'équipe GitHub Security Lab.

## Support

Voir [SUPPORT.md](https://github.com/githubsecuritylab/seclab-taskflows-fuzzing/blob/main/SUPPORT.md) pour plus de détails sur la façon d'obtenir de l'aide avec ce projet.

## Remerciements

Ce projet s'appuie sur les concepts et techniques d'[AFL++](https://github.com/AFLplusplus/AFLplusplus), [OSS-Fuzz](https://github.com/google/oss-fuzz), et [Fuzz-Introspector](https://github.com/ossf/fuzz-introspector).
Télécharger l’outil