
Un benchmark pour évaluer les agents d'IA sur la correction de vulnérabilités de sécurité réelles.
Un benchmark pour évaluer les agents LLM sur la correction de vulnérabilités de sécurité réelles. Les agents s'exécutent dans des conteneurs Docker isolés et sont notés par rapport à la suite de tests de sécurité du mainteneur.
OPENAI_API_KEY, ANTHROPIC_API_KEY, et/ou POOLSIDE_API_KEY dans votre environnement (ou un fichier .env)Installer les dépendances :
pip install poetry
poetry install
Chaque tâche se trouve sous tasks/{CVE-ID}/ et contient :
tasks/CVE-2026-33175/
├── meta.json # GHSA ID, CWE, CVSS, URL du dépôt, SHA vulnérable et corrigé
├── setup.sh # Clone le dépôt, bascule sur le SHA vulnérable, installe les dépendances
├── run_tests.sh # Injecte test_security.py dans le dépôt et exécute pytest
├── test_security.py # Tests de sécurité (xfail sur le code vulnérable, passent sur la correction)
├── advisory.md # Avis GHSA complet (prompt le plus riche)
├── diagnose.md # Description comportementale uniquement — pas de noms de fichiers ou de fonctions
├── locate.md # Fichier et fonction uniquement — pas de description du défaut
└── Dockerfile # Optionnel ; présent uniquement si la tâche nécessite des dépendances système supplémentaires
Exemple de meta.json :
{
"ghsa_id": "GHSA-xxxx-xxxx-xxxx",
"cwe": ["CWE-287"],
"cvss": 9.1,
"repo": {
"url": "https://github.com/org/project",
"vulnerable_sha": "abc123^",
"fixed_sha": "abc123"
}
}
setup.sh est idempotent et peut être réexécuté en toute sécurité. test_security.py reste caché de l'agent pendant l'exécution et n'est injecté qu'après que l'agent a terminé.
python build.py
Ceci construit :
cve-bench/base) — Python 3.12, git, poetry et le harness.cve-bench/{task-id}) — étend la base, copie le répertoire de la tâche et exécute setup.sh.Options :
# Construire uniquement des tâches spécifiques
python build.py --task CVE-2026-33175 CVE-2026-42561
# Ignorer la reconstruction de l'image de base
python build.py --skip-base
Les images de tâches sont construites en parallèle (jusqu'à 5 workers). Si un répertoire de tâche contient un Dockerfile, celui-ci est utilisé à la place du docker/task.Dockerfile générique.
Avant d'exécuter le benchmark, vérifiez que les tests de sécurité de chaque tâche distinguent correctement le code vulnérable du code corrigé :
python validate.py
Pour chaque tâche, cela exécute trois phases dans le conteneur de la tâche :
| Phase | Ce qui est vérifié |
|---|---|
| vulnérable | Les tests de sécurité doivent échouer (ou xfail) sur le SHA vulnérable |
| corrigé | Les tests de sécurité doivent passer sur le SHA corrigé |
| régression | Les tests non liés à la sécurité doivent passer sur le SHA corrigé |
Les résultats sont affichés dans un tableau en direct. Le code de sortie est 1 si une tâche échoue à une phase.
# Valider uniquement des tâches spécifiques
python validate.py --task CVE-2026-33175 GHSA-r758-8hxw-4845
# Ignorer la reconstruction des images avant validation
python validate.py --skip-build
python benchmark.py --model openai:gpt-5.5 poolside:laguna-m.1 --prompt-type advisory
Options :
Fournisseurs supportés :
Chaque exécution produit un fichier de résultat JSON dans results/ :
results/{task-id}__{provider}:{model}__{prompt-type}.json
Les fichiers de résultat existants sont automatiquement ignorés. Les exécutions sont concurrentes entre les tâches (jusqu'à 20 workers), avec une limitation de débit par fournisseur (une requête active par fournisseur à la fois) pour éviter les erreurs 429.
Chaque fichier de résultat est un objet JSON avec la structure suivante :
{
"cve_id": "CVE-2026-33175",
"model_id": "openai:gpt-5.5",
"prompt_type": "advisory",
"timestamp": "2026-05-01T12:00:00",
"model_duration_s": 142.3,
"test_duration_s": 8.1,
"turns": [
{
"tool_calls_and_results": [...],
"input_tokens": 12400,
"output_tokens": 310
}
],
"tests": [
{
"kind": "security",
"name": "test_email_verified",
"outcome": "passed"
}
]
}
tests[].kind est soit "security" (provenant de test_security.py) soit "regression" (provenant de la suite de tests du projet). Une exécution est considérée comme résolue uniquement si tous les tests de sécurité passent et qu'aucun test de régression n'échoue.
python generate_charts.py
Lit tous les fichiers de résultat de results/ et écrit des graphiques SVG dans docs/images/charts/. Nécessite Chrome/Chromium pour l'export sans tête de Bokeh (via chromedriver-binary).
Le harness s'exécute à l'intérieur de chaque conteneur Docker en tant que python -m harness.run. Il est responsable du chargement du prompt, de l'exécution de la boucle agent et de l'écriture du fichier de résultat.
src/harness/
├── run.py # Point d'entrée ; analyse les arguments, connecte les composants, appelle BenchmarkRunner
├── client/
│ ├── factory.py # Analyse provider:model-id, retourne le LLMClient approprié
│ ├── _client.py # LLMClient abstrait, dataclasses ToolCall et LLMTurn
│ ├── anthropic.py # Intégration SDK Anthropic
│ └── oai.py # Intégration SDK OpenAI (également utilisée pour Poolside)
├── agent/
│ ├── core.py # Boucle agent : appelle le client, répartit les appels d'outils, thread les messages
│ └── runner.py # Encapsule Agent, suit le timing et la liste des tours
├── bench/
│ ├── runner.py # Orchestre setup → agent → tests de sécurité → tests de régression
│ ├── result.py # Dataclasses BenchmarkResult et TestResult, sérialisation JSON
│ └── repository.py # Écrit les fichiers de résultat sur le disque
└── task/
├── tools.py # Implémentations des outils : ListFiles, ReadFile, SearchInFiles,
│ # EditFile, CreateFile, DeleteFile, RunPytest
└── prompt_loader.py # Lit advisory.md / diagnose.md / locate.md
Outils disponibles pour l'agent :
Tous les outils valident les chemins par rapport à la racine du dépôt pour empêcher les traversées de répertoires. L'agent n'a pas accès à test_security.py ni à l'historique git.
La boucle agent s'exécute pour un maximum de 20 tours. Si le plafond de tours est atteint, l'exécution est enregistrée telle quelle et les tests de sécurité sont toujours exécutés sur l'état laissé par l'agent dans le dépôt.
tasks/{CVE-ID}/ et ajoutez meta.json, setup.sh, run_tests.sh, test_security.py, advisory.md, diagnose.md, locate.md.setup.sh et run_tests.sh exécutables (chmod +x).python validate.py --task {CVE-ID}.python build.py --task {CVE-ID}.Ce travail a été mené dans le cadre d'une recherche indépendante. Au moment de la réalisation de la recherche et de la préparation de ce dépôt, je n'avais aucune affiliation institutionnelle.
@misc{gattipinheiro2026cvebench,
author = {Gatti Pinheiro, Giovanni},
title = {{CVE-Bench}: Benchmarking {LLM} Agents on Real-World Security Vulnerability Fixes},
year = {2026},
howpublished = {\url{https://giovannigatti.github.io/cve-bench}},
note = {Code available at \url{https://github.com/GiovanniGatti/cve-bench}}
}
MIT — voir LICENSE.
| Flag | Description | Défaut |
|---|
--model | Une ou plusieurs chaînes provider:model-id | tous les modèles configurés |
--prompt-type | advisory, diagnose, locate, ou toute combinaison | les trois |
--task | Un ou plusieurs identifiants de tâche | toutes les tâches |
--clean | Supprimer les résultats existants pour la portée sélectionnée avant de commencer | désactivé |
| Fournisseur | Format | Variable d'environnement de la clé API |
|---|
| OpenAI | openai:gpt-5.5 | OPENAI_API_KEY |
| Anthropic | anthropic:claude-haiku-4-5-20251001 | ANTHROPIC_API_KEY |
| Poolside | poolside:laguna-m.1 | POOLSIDE_API_KEY |
| Outil | Description |
|---|
list_files | Lister les fichiers et répertoires dans le dépôt |
read_file | Lire le contenu d'un fichier, éventuellement une plage de lignes |
search_in_files | Recherche regex dans le code avec un glob de fichier optionnel |
edit_file | Remplacer une plage de lignes dans un fichier existant |
create_file | Créer un nouveau fichier |
delete_file | Supprimer un fichier |
run_pytest | Exécuter la suite de tests du projet ; retourne un rapport JSON |