
ИИ-агенты пентеста становятся всё более убедительными в роли наступательных систем безопасности, однако современные бенчмарки по-прежнему дают ограниченное представление о том, какие системы покажут наилучшие результаты на реальных целях. Большинство существующих оценок проверяют и оптимизируют заранее заданные цели, такие как захват флагов, удалённое выполнение кода, воспроизведение эксплойтов или схожесть траекторий, в упрощённых или узких условиях. Эти бенчмарки ценны для измерения ограниченных возможностей, но они не в полной мере отражают сложность, открытое исследование и стратегическое принятие решений, необходимые в реалистичном пентесте. Мы представляем практическую систему оценки, которая смещает акцент с выполнения задач на подтверждённое обнаружение уязвимостей, позволяя проводить оценку на достаточно сложных целях, охватывающих множество поверхностей атаки и классов уязвимостей. Система сочетает структурированные эталонные данные (ground truth) с семантическим сопоставлением на основе LLM для выявления уязвимостей, разрешение на основе двудольных графов для оценки находок в условиях реалистичной неоднозначности, непрерывное сопровождение эталонных данных, повторную и кумулятивную оценку стохастических агентов, метрики эффективности и выбор сокращённого набора тестов для устойчивого экспериментирования. Эта методология расширяет современный уровень техники, обеспечивая более реалистичное и операционно значимое сравнение ИИ-агентов пентеста. Для обеспечения воспроизводимости мы дополнительно публикуем эталонные данные с разметкой экспертов и код для предложенного протокола оценки.
Конвейер оценки для инструментов тестирования безопасности. Сравнивает находки инструментов с эталонными наборами данных с помощью сопоставления на основе LLM и вычисляет метрики precision, recall, F1 и F0.5.
poetry install
Требуются Python 3.11+ и установленный Poetry.
# 1. Set your LLM API key
export OPENAI_API_KEY="..."
# 2. Run evaluation
ethibench evaluate ./my_experiment --dataset path/to/dataset.yaml
# 3. View results
cat ./my_experiment/evaluation_outputs/summary.md
ethibench evaluateЗапускает полный конвейер оценки для каталога эксперимента.
ethibench evaluate <experiment_dir> --dataset <dataset.yaml> [options]
# Batch: evaluate all experiments in a folder
ethibench evaluate --parent-dir final_experiments/ --dataset <dataset.yaml>
# Force re-evaluation (ignore cached artifacts)
ethibench evaluate <experiment_dir> --dataset <dataset.yaml> --force
Аргументы:
experiment_dir — (необязательно) Каталог, содержащий подкаталоги целей (или подкаталоги run_*, каждый из которых содержит подкаталоги целей). Можно не указывать при использовании --parent-dir.Опции:
--dataset, -d — (обязательно) Путь к YAML-файлу набора данных.--gt-dir, -g — Каталог эталонных данных. По умолчанию — gt/ рядом с YAML-файлом набора данных.--output-dir, -o — Каталог вывода. По умолчанию — evaluation_outputs/ внутри каталога эксперимента. Игнорируется в пакетном режиме.--replicates, -n — Количество повторов LLM-сопоставления (по умолчанию: 1).--force, -f — Повторно выполнить все шаги, игнорируя кэшированные артефакты. По умолчанию повторно используются существующие промежуточные результаты (сырые сопоставления, двудольные сопоставления, метрики).--parent-dir, -p — Родительский каталог, содержащий несколько каталогов экспериментов для пакетной оценки. Все непосредственные подкаталоги рассматриваются как эксперименты.Что он делает:
target_id), загружает каждый findings.jsonl, присваивает subset_name из YAML-файла набора данных.metrics.json для каждой цели, если он присутствует, агрегирует стоимость/токены/длительность.evaluation_outputs/plots/.evaluation_outputs/summary.md.ethibench analyzeЗапускает инструменты анализа на существующих результатах оценки.
ethibench analyze <experiment_dir> --dataset <dataset.yaml> [options]
# Batch: analyze all experiments and produce aggregated results
ethibench analyze --parent-dir final_experiments/ --dataset <dataset.yaml>
Аргументы:
experiment_dir — (необязательно) Каталог эксперимента для анализа. Можно не указывать при использовании --parent-dir.Опции:
--dataset, -d — (обязательно) Путь к YAML-файлу набора данных.--gt-dir, -g — Каталог эталонных данных. По умолчанию — gt/ рядом с YAML-файлом набора данных.--output-dir, -o — Каталог результатов оценки. По умолчанию — evaluation_outputs/ внутри каталога эксперимента.--parent-dir, -p — Родительский каталог, содержащий несколько каталогов экспериментов для пакетного анализа. Создаёт анализ по каждому эксперименту и агрегированные результаты.Результаты по каждому эксперименту (evaluation_outputs/analysis/):
duplicates.json — находки, сопоставленные при сыром сопоставлении, но удалённые двудольной оптимизацией.unmatched.json — находки без соответствия эталонным данным (ложные срабатывания).statistics.json — статистика покрытия GT, распределение находок по каждой записи GT.Агрегированные результаты (только с --parent-dir, в <parent-dir>/aggregated_analysis/):
all_duplicates.jsonl — все дублирующиеся находки во всех экспериментах (JSONL, полные объекты находок с полем experiment).all_false_positives.jsonl — все несопоставленные/ложноположительные находки во всех экспериментах (формат JSONL).gt_statistics_avg.json — усреднённое покрытие GT по каждому поднабору, а также сводка покрытия по каждому эксперименту.ethibench compareСравнивает результаты оценки нескольких экспериментов, создавая диаграммы «бок о бок» и сводный отчёт. Каждый эксперимент уже должен иметь результаты оценки (сначала выполните ethibench evaluate). Метками всегда служат имена каталогов.
# Explicit experiment directories
ethibench compare exp-gpt4o/ exp-claude/ --output-dir comparison/
# Auto-discover all experiments under a parent folder
ethibench compare --parent-dir all-experiments/ --output-dir comparison/
# Mix: explicit dirs + auto-discovery
ethibench compare exp-extra/ --parent-dir all-experiments/ --output-dir comparison/
Аргументы:
experiment_dirs — (необязательно) Один или несколько каталогов экспериментов для явного включения.Опции:
--output-dir, -o — (обязательно) Каталог вывода для результатов сравнения.--parent-dir, -p — Родительский каталог для автоматического обнаружения экспериментов. Включаются все непосредственные подкаталоги, содержащие папку evaluation_outputs/, отсортированные по алфавиту. Можно комбинировать с явно указанными experiment_dirs.Результаты (в --output-dir):
comparison.json — необработанные данные сравнения для всех экспериментов.plots/ — PNG-диаграммы «бок о бок».comparison.md — сводка в формате Markdown.pairwise_comparison.md — попарное статистическое сравнение A/B (4 лучших эксперимента по F1).pairwise_comparison.tex — версия попарной таблицы в формате LaTeX.cumulative-analysis/ — (если существуют кумулятивные данные) дельта-анализ, сравнивающий усреднённый и кумулятивный F1, а также диаграммы кумулятивного сравнения.findings.jsonl)По одному JSON-объекту в строке. Обязательные поля: title, description. Необязательные: url, cwe, severity, score, steps, evidence, metadata и т. д.
Каждый findings.jsonl находится внутри каталога цели — имя каталога определяет, к какой цели относятся находки.
{"title": "SQL Injection in Login", "description": "User input not sanitized", "cwe": "89"}
*_gt.jsonl)По одному JSON-объекту в строке.
{"id": "gt-001", "name": "SQL Injection", "subset_name": "MyApp", "target_id": "app", "category": "CWE-89", "description": "Database query vulnerability", "cvss": 9.8}
- subset: "MyApp"
weight: 1.0
targets:
- target_id: "app"
Значение target_id должно совпадать с именем каталога внутри папки каждого прогона. При оценке ethibench сканирует каталог прогона на наличие подкаталогов, соответствующих известным значениям target_id, загружает их findings.jsonl и приписывает их к соответствующему поднабору. Необязательное поле gt_file задаёт путь к пользовательскому файлу GT.
Вся конфигурация осуществляется через переменные окружения:
Одиночный прогон:
my_experiment/
├── app.example.com/ # target_id as directory name
│ ├── findings.jsonl # findings for this target
│ └── metrics.json # optional: cost/token info
├── api.example.com/
│ ├── findings.jsonl
│ └── metrics.json
Несколько прогонов:
my_experiment/
├── run_001/
│ ├── app.example.com/
│ │ ├── findings.jsonl
│ │ └── metrics.json
│ └── api.example.com/
│ └── findings.jsonl
├── run_002/
│ ├── app.example.com/
│ │ └── findings.jsonl
│ └── api.example.com/
│ └── findings.jsonl
my_experiment/
└── evaluation_outputs/
├── findings_parsed.jsonl # unified findings with target_id/subset_name
├── raw_matchings/ # Step 1: LLM comparison results
│ └── matchings_MyApp.json
├── matchings/ # Step 2: optimal 1-to-1 assignments
│ └── matchings_MyApp.json
├── results/ # Step 3: per-subset metrics
│ └── evaluation_results_MyApp.json
├── results_avg/ # averaged across replicates
├── results_avg_all/ # averaged across runs (multi-run only)
├── metrics_summary.json # aggregated cost/token metrics
├── plots/ # PNG charts
│ ├── metrics_per_subset.png
│ ├── counts_per_subset.png
│ ├── overall_unweighted.png
│ ├── per_target_costs.png
│ └── per_target_duration.png
├── cumulative-analysis/ # multi-run only: merged findings + overlap
│ ├── findings_parsed.jsonl
│ ├── raw_matchings/
│ ├── matchings/
│ ├── results/
│ ├── results_avg/
│ ├── run_overlap.json # GT-level overlap between runs
│ └── plots/
│ ├── metrics_per_subset.png
│ ├── counts_per_subset.png
│ ├── overall_unweighted.png
│ ├── jaccard_similarity.png
│ └── vulnerability_frequency.png
├── analysis/ # from `ethibench analyze`
│ ├── duplicates.json
│ ├── unmatched.json
│ └── statistics.json
└── summary.md
Результаты пакетного анализа (с --parent-dir):
parent_dir/
├── experiment_a/
│ └── evaluation_outputs/analysis/ # per-experiment analysis
├── experiment_b/
│ └── evaluation_outputs/analysis/
└── aggregated_analysis/ # cross-experiment aggregation
├── all_duplicates.jsonl # all duplicates as JSONL
├── all_false_positives.jsonl # all false positives as JSONL
└── gt_statistics_avg.json # averaged GT coverage stats
Для экспериментов с несколькими прогонами (подкаталоги run_*) ethibench автоматически создаёт кумулятивный анализ, который объединяет все прогоны в единый комбинированный набор данных и заново вычисляет двудольное сопоставление и метрики на объединённых данных. Этот шаг выполняется последним в ethibench evaluate для экспериментов с несколькими прогонами.
findings_parsed.jsonl из всех прогонов (без дедупликации).Анализ пересечения (run_overlap.json) отвечает на вопрос: обнаруживают ли разные прогоны одни и те же уязвимости? Он использует двудольные сопоставления (авторитетные назначения TP) из каждого отдельного прогона.
Для каждого поднабора и в целом:
found_by_all, found_by_some, found_by_one, found_by_none.jaccard_similarity.png — столбчатая диаграмма попарного сходства Жаккара между прогонами с пунктирной линией, показывающей среднее значение.vulnerability_frequency.png — столбчатая диаграмма, показывающая, сколько эталонных уязвимостей было найдено ровно N прогонами (цветовая кодировка от красного = 0 через жёлтый к зелёному = все).evaluation_outputs/cumulative-analysis/
├── findings_parsed.jsonl # merged from all runs
├── raw_matchings/ # merged from all runs
├── matchings/ # bipartite matching on merged data
├── results/ # per-subset metrics
├── results_avg/ # averaged + weighted/unweighted overall
├── run_overlap.json # GT-level overlap between runs
└── plots/
├── metrics_per_subset.png
├── counts_per_subset.png
├── overall_unweighted.png
├── jaccard_similarity.png
└── vulnerability_frequency.png
Сырое сопоставление: каждая находка сравнивается с каждой записью эталонных данных с помощью LLM. LLM принимает решение ДА/НЕТ для каждой пары. Это создаёт отображение «многие ко многим».
Двудольное сопоставление: венгерский алгоритм (scipy.optimize.linear_sum_assignment) находит оптимальное взаимно-однозначное соответствие, максимизирующее количество сопоставленных пар.
Классификация:
Метрики:
src/ethibench/
├── cli.py # Click CLI entry points (evaluate, convert-report, analyze, compare)
├── config.py # Environment variable configuration
├── models.py # Pydantic data models
├── datasets.py # Dataset/target YAML management
├── llm.py # LLM provider factory
├── evaluate.py # Core 3-step evaluation pipeline
├── results.py # Results aggregation and averaging
├── metrics.py # Per-target cost/token/duration metrics
├── convert_report.py # Report → findings conversion
├── cumulative_analysis.py # Cross-run cumulative analysis + overlap
├── pairwise.py # Pairwise A/B statistical comparison (t-test, Cohen's d)
├── plots.py # PNG chart generation (eval, cumulative, comparison)
├── report.py # Markdown summary generation
└── analysis/
├── duplicates.py # Duplicate finding detection
├── unmatched.py # Unmatched finding extraction
└── statistics.py # GT coverage statistics
| Variable | Default | Description |
|---|
ETHIBENCH_LLM_PROVIDER | openai | Провайдер LLM: openai, anthropic, ollama, gemini |
ETHIBENCH_LLM_MODEL | gpt-5.4-mini | Название модели |
ETHIBENCH_TEMPERATURE | 0.3 | Температура сэмплирования |
ETHIBENCH_API_URL | — | Пользовательская конечная точка API (для Ollama или совместимых API) |
ETHIBENCH_CONCURRENCY | 50 | Максимальное количество одновременных LLM-вызовов |
ETHIBENCH_MAX_RETRIES | 5 | Максимальное количество повторов на один LLM-вызов |
ETHIBENCH_MAX_PARALLEL_RUNS | 3 | Максимальное количество прогонов, оцениваемых параллельно в рамках эксперимента |
ANTHROPIC_API_KEY | — | Ключ API Anthropic |
OPENAI_API_KEY | — | Ключ API OpenAI |
GEMINI_API_KEY | — | Ключ API Google Gemini |