EN
en direct

GitHub Security Lab livre un agent qui fuzze un dépôt C/C++ de bout en bout

Le 24 septembre 2026, GitHub Security Lab a publié un pipeline de fuzzing autonome qui écrit ses harnais, lit sa couverture et rédige ses rapports de vulnérabilité. Le goulot du fuzzing — l’attention humaine — est délégué à un LLM, mais le code s’exécute sans conteneur sur l’hôte.

Une fine aiguille métallique effleurant la surface sombre d’une puce, un seul point de contact brillant d’une lueur ambre.

24 septembre 2026. Antonio Morales, chercheur au GitHub Security Lab, publie le Fuzzing Taskflow, un pipeline de fuzzing autonome pour les projets C/C++. 2014. Michal Zalewski publiait AFL, le fuzzer à couverture de code qui a popularisé la discipline. 2016. Google lançait OSS-Fuzz, qui a industrialisé le fuzzing continu de l’open source. Pourquoi c’est important : le goulot du fuzzing n’a jamais été le calcul, mais l’attention humaine — et c’est elle que ce pipeline délègue à un LLM, du premier harnais jusqu’au rapport de vulnérabilité.

Un pipeline qui va du dépôt au rapport

Le Fuzzing Taskflow est construit sur le framework Taskflow Agent du GitHub Security Lab, dédié à l’automatisation de la sécurité pilotée par LLM. La promesse tient en une phrase : pointez-le vers un dépôt GitHub, il fait le reste.

Concrètement, l’agent identifie les points d’entrée pertinents, analyse le système de build, écrit les harnais, lance AFL++, lit les rapports de couverture, améliore les harnais, trie chaque crash et rédige un rapport de vulnérabilité pour chaque bug distinct — sans supervision humaine entre les étapes. L’exemple donné dans l’annonce est explicite : lancer la campagne sur xz, le projet dont la porte dérobée a ébranlé la supply chain en 2024, ou sur cJSON pour un simple test de fumée.

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

L’architecture tient en trois couches. Un pilote shell, run_fuzzing.sh, enchaîne les étapes du pipeline. Une série de YAML de taskflows — un par étape — porte les prompts qui disent à l’agent quoi faire. Un ensemble d’outils MCP exécute le travail réel : lancer AFL, compiler un harnais, stocker un crash, lire un rapport de couverture. La règle de conception affichée est une séparation stricte des responsabilités : le LLM décide, les outils exécutent. L’agent ne touche jamais AFL ou clang directement ; il compose le pipeline à partir de ces briques. Tout l’état transite par une base SQLite, fuzz_context.db, jamais par la mémoire partagée entre étapes.

La boucle de couverture, cœur du système

La partie qui automatise le plus fidèlement le travail manuel est la boucle de couverture. Améliorer la couverture d’un fuzzer à la main est un cycle bien connu : on mesure la couverture, on cherche les branches non atteintes, puis on écrit un harnais ou un seed pour les toucher. Le Fuzzing Taskflow confie ces deux étapes à l’agent.

À chaque itération, pour chaque harnais, l’agent lance AFL sur un budget de temps, rejoue la file d’attente contre le binaire de couverture pour obtenir un vrai rapport, puis lit la liste des branches non couvertes. Il choisit alors une action parmi un petit ensemble : ajouter un seed conçu pour atteindre une branche, modifier le harnais pour appeler une API supplémentaire, enrichir le dictionnaire AFL avec les constantes magiques qu’une comparaison vérifie, ou simplement ignorer l’écart s’il s’agit d’un chemin d’erreur froid ou de code fournisseur sans intérêt.

Les budgets de temps doublent à chaque itération — 30 s, 60 s, 120 s, 240 s, 480 s, 960 s, soit environ 32 minutes par cible. L’idée est de dépenser des rounds courts et bon marché au début, quand la couverture facile est abondante, puis des rounds longs quand le fuzzer doit franchir une garde difficile. L’arrêt est gouverné par une détection de plateau : dès que deux itérations consécutives gagnent chacune moins d’un seuil configurable — 1 % de couverture de ligne absolue par défaut — la boucle conclut à des rendements décroissants et passe à la suite.

Un fuzzing qui comprend la structure des formats

Les mutations octet-à-octet d’AFL excellent sur les formats binaires, mais peinent sur les entrées structurées et textuelles. Le pipeline embarque donc quatre mécanismes complémentaires pour produire des entrées structure-aware.

Pour les formats reconnus — JSON, XML, expressions régulières, PNG, binaires TLV à préfixe de longueur — il livre des dictionnaires AFL préconstruits et des fichiers LLVMFuzzerCustomMutator en C. Le mutateur JSON pratique le splicing de jetons et la duplication de crochets équilibrés ; celui d’XML connaît les balises, les entités et les jetons billion-laughs ; celui des regex porte de vrais motifs ReDoS. Chaque mutateur délègue la moitié de ses mutations au mutateur octet par défaut, pour conserver l’aléatoire du moteur au lieu de le combattre.

Pour les formats inconnus, il génère un mutateur à la volée en scannant les fichiers .c/h de la cible, extrait les littéraux de chaînes et les constantes numériques 32 bits, puis les utilise comme jetons de splice. L’intuition est simple : les valeurs magiques les plus intéressantes qu’un parseur vérifie sont presque toujours écrites quelque part dans son propre code source. Un opérateur de splice de corpus complète le dispositif, en recombinant des sous-régions de fichiers existants d’une façon que le havoc d’AFL ne fait pas bien.

Le tri des crashs, désormais automatisé

Trouver un crash n’est que la moitié du travail. Le triage — souvent la partie la plus fastidieuse — est l’autre endroit où l’agent brille. Trois étapes s’enchaînent après la boucle de fuzzing.

Chaque crash est minimisé avec afl-tmin, rejoué sous ASan pour capturer une trace de pile, puis dédupliqué par un hachage du sommet de pile — cadres normalisés, avec gabarits, espaces de noms inline et suffixes LTO supprimés pour que des crashs sémantiquement identiques fusionnent. Les crashs déjà connus sont rejoués contre le binaire courant pour vérifier si un correctif amont les a résolus. Enfin, l’agent lit le harnais et la fonction fautive, remonte la chaîne d’appel depuis l’API publique, et rédige un rapport Markdown par crash, avec un verdict parmi vulnerability, library_hardening, harness_bug, OOM, timeout, assertion_failure et duplicate.

La distinction entre une vraie vulnérabilité — atteignable et exploitable via une API publique — et un simple harness_bug est précisément le jugement qui exigeait autrefois de tracer le code à la main. Chaque rapport inclut une analyse de cause racine avec références fichier:ligne, un argument de portée, une évaluation d’exploitabilité, un correctif proposé en diff unifié et une ébauche de test de régression. L’auteur est transparent sur une limite : les correctifs proposés sont marqués « revue requise », car l’analyse de l’agent est bornée par la compréhension que le modèle a du code cible — et il se trompe parfois.

La limite que l’auteur assume : pas de conteneur

Un avertissement, placé avant même le mode d’emploi, mérite toute l’attention d’un RSSI ou d’un SRE. Ce taskflow exécute afl-fuzz, clang et des commandes de build arbitraires choisies par le LLM directement sur l’hôte, sans conteneur intermédiaire. Un agent victime d’une prompt injection pourrait, en principe, faire tout ce que votre utilisateur peut faire.

La recommandation de l’auteur est sans ambiguïté : ne le lancer que dans un environnement jetable — un Codespace ou une VM jetable — et sans privilèges élevés. Le modèle par défaut est Claude Sonnet 5, retenu parce qu’il a passé tous les tests internes sans accroc. L’auteur rappelle enfin qu’un tableau de bord HTML en direct, publié sur le port 8765, permet de suivre la campagne en temps réel — impulsion par harnais, tendance de couverture avec sparklines, carte de chaleur des crashs et chronologie d’itération.

Verdict

Si vous maintenez un projet C/C++, essayez-le sur un dépôt jamais fuzzé : c’est le chemin le plus court pour un premier harnais et un premier tri de crashs, et le code est libre. Si votre projet est déjà dans OSS-Fuzz, l’intérêt est ailleurs — augmenter la couverture en laissant l’agent chasser les branches que vos harnais n’atteignent pas. Quel que soit votre cas, exécutez-le dans une VM jetable sans élévation de privilèges et traitez chaque verdict de l’agent comme un point de départ pour un humain, jamais comme une conclusion. La leçon générale dépasse ce projet : quand vous confiez un pipeline de sécurité à un LLM, gardez la séparation des responsabilités — à l’agent la décision, à vos outils l’exécution, et à vous la revue.

Références

Le brief cyber, chaque mardi

Les failles qui comptent, les correctifs à appliquer, en dix minutes de lecture.

Pas de spam. Désinscription en un clic.
à lire ensuite

Sur le même sujet

OpenTelemetry et Prometheus convergent enfin, et les chiffres 2026 le confirment

Une enquête 2026 montre que l’interopérabilité entre OpenTelemetry et Prometheus a nettement progressé : la note de facilité d’usage grimpe de 3,1 à 3,6 et la part de ceux qui les jugent difficiles à combiner chute de 29 % à 10 %. Pour une équipe SRE qui hésite encore, le moment est venu de consolider sur le Collector OTel sans abandonner Prometheus.

Une adresse GitLab « Email work item » fuitée en public ouvre des merge requests à votre place

Le 24 septembre 2026, Aikido a révélé que les adresses « Email work item to this project » de GitLab, générées avec un jeton longue durée et publiées par erreur dans des README, laissent un attaquant créer des merge requests ou pousser du code à la place du titulaire. Cherchez ces adresses dans vos dépôts et réinitialisez les jetons exposés.

← Retour au fil

Tapez au moins deux caractères.

↑ ↓ naviguer ↵ ouvrir esc fermer