
Un benchmark per valutare gli agenti AI nella correzione di vulnerabilità di sicurezza reali.
Un benchmark per valutare agenti LLM nella correzione di vulnerabilità di sicurezza reali. Gli agenti vengono eseguiti in container Docker in sandbox e vengono valutati tramite la suite di test di sicurezza del maintainer.
OPENAI_API_KEY, ANTHROPIC_API_KEY e/o POOLSIDE_API_KEY nel tuo ambiente (o in un file .env)Installa le dipendenze:
pip install poetry
poetry install
Ogni task si trova in tasks/{CVE-ID}/ e contiene:
tasks/CVE-2026-33175/
├── meta.json # ID GHSA, CWE, CVSS, URL del repo, SHA vulnerabile e corretta
├── setup.sh # Clona il repo, fa checkout dello SHA vulnerabile, installa le dipendenze
├── run_tests.sh # Inietta test_security.py nel repo ed esegue pytest
├── test_security.py # Test di sicurezza (xfail sul codice vulnerabile, passano con la correzione)
├── advisory.md # Advisory GHSA completo (prompt più ricco)
├── diagnose.md # Solo descrizione comportamentale — nessun nome di file o funzione
├── locate.md # Solo file e funzione — nessuna descrizione del difetto
└── Dockerfile # Opzionale; presente solo quando il task richiede dipendenze di sistema aggiuntive
Esempio di 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 è idempotente e può essere rieseguito in sicurezza. test_security.py viene tenuto nascosto all'agente durante l'esecuzione e viene iniettato solo dopo che l'agente ha terminato.
python build.py
Questo crea:
cve-bench/base) — Python 3.12, git, poetry e l'harness.cve-bench/{task-id}) — estende la base, copia la directory del task ed esegue setup.sh.Opzioni:
# Crea solo i task specificati
python build.py --task CVE-2026-33175 CVE-2026-42561
# Salta la ricostruzione dell'immagine base
python build.py --skip-base
Le immagini dei task vengono create in parallelo (fino a 5 worker). Se una directory di task contiene un Dockerfile, viene usato quello al posto del docker/task.Dockerfile generico.
Prima di eseguire il benchmark, verifica che i test di sicurezza di ogni task distinguano correttamente il codice vulnerabile da quello corretto:
python validate.py
Per ogni task, questo esegue tre fasi all'interno del container del task:
| Fase | Cosa verifica |
|---|---|
| vulnerable | I test di sicurezza devono fallire (o xfail) sullo SHA vulnerabile |
| fixed | I test di sicurezza devono passare sullo SHA corretto |
| regression | I test non di sicurezza devono passare sullo SHA corretto |
I risultati vengono mostrati come una tabella live. Il codice di uscita è 1 se un qualsiasi task fallisce una qualsiasi fase.
# Valida solo i task specificati
python validate.py --task CVE-2026-33175 GHSA-r758-8hxw-4845
# Salta la ricostruzione delle immagini prima della validazione
python validate.py --skip-build
python benchmark.py --model openai:gpt-5.5 poolside:laguna-m.1 --prompt-type advisory
Opzioni:
Provider supportati:
Ogni esecuzione produce un file JSON dei risultati in results/:
results/{task-id}__{provider}:{model}__{prompt-type}.json
I file dei risultati esistenti vengono saltati automaticamente. Le esecuzioni procedono in modo concorrente tra i task (fino a 20 worker), con rate limiting per provider (una richiesta attiva per provider alla volta) per evitare errori 429.
Ogni file di risultato è un oggetto JSON con la seguente struttura:
{
"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 è "security" (da test_security.py) oppure "regression" (dalla suite di test del progetto). Un'esecuzione è considerata risolta solo se tutti i test di sicurezza passano e nessun test di regressione fallisce.
python generate_charts.py
Legge tutti i file dei risultati da results/ e scrive i grafici SVG in docs/images/charts/. Richiede Chrome/Chromium per l'export headless di Bokeh (tramite chromedriver-binary).
L'harness viene eseguito all'interno di ogni container Docker come python -m harness.run. Si occupa di caricare il prompt, eseguire il loop agentico e scrivere il file dei risultati.
src/harness/
├── run.py # Punto di ingresso; analizza gli argomenti, collega i componenti, chiama BenchmarkRunner
├── client/
│ ├── factory.py # Analizza provider:model-id, restituisce il LLMClient corretto
│ ├── _client.py # Dataclass astratte LLMClient, ToolCall e LLMTurn
│ ├── anthropic.py # Integrazione SDK Anthropic
│ └── oai.py # Integrazione SDK OpenAI (usata anche per Poolside)
├── agent/
│ ├── core.py # Loop agentico: chiama il client, distribuisce le tool call, gestisce i messaggi
│ └── runner.py # Incapsula Agent, traccia tempi e lista dei turni
├── bench/
│ ├── runner.py # Orchestra: setup → agente → test di sicurezza → test di regressione
│ ├── result.py # Dataclass BenchmarkResult e TestResult, serializzazione JSON
│ └── repository.py # Scrive i file dei risultati su disco
└── task/
├── tools.py # Implementazioni degli strumenti: ListFiles, ReadFile, SearchInFiles,
│ # EditFile, CreateFile, DeleteFile, RunPytest
└── prompt_loader.py # Legge advisory.md / diagnose.md / locate.md
Strumenti disponibili per l'agente:
Tutti gli strumenti validano i percorsi rispetto alla radice del repository per prevenire directory traversal. L'agente non ha accesso a test_security.py né alla cronologia git.
Il loop dell'agente esegue al massimo 20 turni. Se viene raggiunto il tetto massimo di turni, l'esecuzione viene registrata così com'è e i test di sicurezza vengono comunque eseguiti sullo stato del repository lasciato dall'agente.
tasks/{CVE-ID}/ e aggiungi meta.json, setup.sh, run_tests.sh, test_security.py, advisory.md, diagnose.md, locate.md.setup.sh e run_tests.sh (chmod +x).python validate.py --task {CVE-ID}.python build.py --task {CVE-ID}.Questo lavoro è stato condotto come ricerca indipendente. Al momento di svolgere la ricerca e di preparare questo repository, non avevo alcuna affiliazione istituzionale.
@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 — vedi LICENSE.
| Flag | Descrizione | Default |
|---|
--model | Una o più stringhe provider:model-id | tutti i modelli configurati |
--prompt-type | advisory, diagnose, locate o qualsiasi combinazione | tutti e tre |
--task | Uno o più ID di task | tutti i task |
--clean | Elimina i risultati esistenti per l'ambito selezionato prima di iniziare | disattivato |
| Provider | Formato | Variabile d'ambiente per la API key |
|---|
| 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 |
| Tool | Descrizione |
|---|
list_files | Elenca file e directory nel repository |
read_file | Legge il contenuto di un file, opzionalmente un intervallo di righe |
search_in_files | Ricerca regex nell'intero codebase con glob opzionale sui file |
edit_file | Sostituisce un intervallo di righe in un file esistente |
create_file | Crea un nuovo file |
delete_file | Elimina un file |
run_pytest | Esegue la suite di test del progetto e restituisce un report JSON |