Аудит безопасности: Автоисправление

Аудит безопасности: Автоисправление

Автоматическая генерация исправлений для уязвимостей, обнаруженных анализом потоков данных (анализ заражения данных).

Обзор

Движок автоисправлений CodeGraph берет обнаруженные уязвимости (пути распространения данных от ненадежных источников к опасным приемникам) и генерирует конкретные исправления. Используются две стратегии:

  1. Шаблонная — шаблоны исправлений на основе сопоставления с образцом для известных типов уязвимостей (высокая уверенность, >0.8)
  2. LLM — откат к генерации через LLM, когда ни один шаблон не подходит (пониженная уверенность, <=0.59)

Все исправления представлены в формате unified diff. В режиме только чтения (по умолчанию) файлы не модифицируются.

Быстрый старт

CLI

# Аудит безопасности с предложениями автоисправлений
python -m src.cli audit --db data/projects/postgres.duckdb --autofix

# Неинтерактивный режим для CI
python -m src.cli exec --prompt "Устрани все обнаруженные SQL-инъекции" \
    --sandbox read-only --output-file results.json

TUI

/scenario security "Найди SQL-инъекции" --autofix

REST API

curl -X POST http://localhost:8000/api/v1/security/autofix \
  -H "Content-Type: application/json" \
  -d '{"method_name": "process_query"}'

MCP (ИИ-ассистент)

codegraph_autofix(method_name="process_query", cwe="CWE-89")

Как это работает

TaintPath (путь распространения)
    |
    v
AutofixEngine
    |
    +---> Парсинг sink_location -> (файл, строка)
    |
    +---> Чтение исходного кода (настраиваемое окно контекста)
    |
    +---> Определение типа уязвимости по sink_category
    |
    +---> Попытка шаблонного исправления (AutofixGenerator)
    |         |
    |         +---> Совпадение? Возврат FixSuggestion (strategy="template")
    |         |
    |         +---> Нет совпадения? Передача в LLM
    |
    +---> Откат на LLM (PromptBuilder + поставщик LLM)
    |         |
    |         +---> Построение структурированного промпта с контекстом потока данных
    |         +---> Вызов настроенного поставщика LLM
    |         +---> Парсинг кода из ответа
    |         +---> Возврат FixSuggestion (strategy="llm")
    |
    +---> DiffValidator
    |         |
    |         +---> Проверка наличия исходного кода в файле
    |         +---> Проверка минимальности изменений
    |         +---> Генерация unified diff
    |
    v
AutofixResult (diff, уверенность, стратегия, валидация)

Поддерживаемые типы уязвимостей

Уязвимость CWE Языки Шаблоны
SQL-инъекция CWE-89 C, Python, Go sprintf->snprintf, %-формат->параметры, fstring->параметры, конкатенация->параметры, Sprintf->$1
Переполнение буфера CWE-120 C, Python, Go strcpy->strncpy, sprintf->snprintf, ограничение ctypes, CGO strncpy
Инъекция команд CWE-78 C, Python, Go system->execv, shell=True->shlex, bash -c->прямой вызов
Разыменование NULL CWE-476 C Проверка NULL через if, проверка через Assert
Использование после освобождения CWE-416 C NULL после free
Утечка информации CWE-200 C Санитизация сообщений об ошибках

Оценка уверенности

Стратегия Диапазон уверенности Значение
Шаблон (простое совпадение) 0.8 - 1.0 Высокая уверенность, безопасно применять
Шаблон (сложная трансформация) 0.6 - 0.8 Хорошая уверенность, рекомендуется проверка
LLM-сгенерированное <= 0.59 Пониженная уверенность, требуется ручная проверка
Неудачная валидация 0.0 Diff не применяется корректно

Расчет уверенности: - База: autofix_base (по умолчанию 0.7) - Бонус простых шаблонов: +autofix_pattern_boost (по умолчанию +0.2) - Штраф сложных трансформаций: +autofix_complexity_penalty (по умолчанию -0.1) - Бонус короткого кода: +autofix_context_boost (по умолчанию +0.1)

Справочник по конфигурации

В config.yaml:

autofix:
  enabled: true                    # Включить движок автоисправлений
  context_lines_before: 5          # Строк контекста до целевой строки
  context_lines_after: 5           # Строк контекста после целевой строки
  llm_max_confidence: 0.6          # Максимальная уверенность для LLM-исправлений
  llm_temperature: 0.1             # Температура LLM (низкая для детерминизма)
  llm_max_tokens: 2048             # Максимум токенов в ответе LLM
  max_fixes_per_run: 10            # Ограничение исправлений за запуск
  require_approval: true           # Требовать подтверждения перед применением

Настройка уверенности в config.yaml в секции workflows.handlers.confidence_settings:

confidence_settings:
  autofix_base: 0.7
  autofix_pattern_boost: 0.2
  autofix_complexity_penalty: -0.1
  autofix_context_boost: 0.1

Процесс одобрения

При require_approval: true (по умолчанию) исправления никогда не применяются автоматически:

  • Интерактивный режим (TUI/CLI): Каждое исправление показывается с diff для принятия/отклонения
  • Режим CI (exec): Исправления возвращаются как структурированный JSON без применения
  • MCP-сервер: Всегда только чтение, возвращает только diff

Решения по одобрению: - accept — применить это исправление - acceptForSession — автоматически одобрять аналогичные исправления (тот же класс CWE) - decline — пропустить это исправление - cancel — прервать весь процесс автоисправления

Расширение доменными шаблонами

Доменные шаблоны автоисправлений загружаются из YAML-конфигурации активного доменного плагина. Для добавления шаблонов нового домена:

  1. Добавьте шаблоны в src/domains/{name}/config/security.yaml в секцию autofix_patterns:
autofix_patterns:
  sql_injection:
    - pattern_name: "domain_specific_fix"
      pattern_regex: "dangerous_func\\((.+?)\\)"
      replacement_template: "safe_func({param})"
      explanation: "Используйте safe_func() вместо dangerous_func()"
  1. AutofixGenerator автоматически загрузит их через get_autofix_patterns_from_plugin().

Примеры

Исправление SQL-инъекции (C)

До:

sprintf(query, "SELECT * FROM t WHERE id = %s", user_input);

После:

snprintf(query, sizeof(query), "SELECT * FROM t WHERE id = %s", user_input);

Исправление переполнения буфера (C)

До:

strcpy(dest, src);

После:

strncpy(dest, src, sizeof(dest) - 1); dest[sizeof(dest) - 1] = '\0';

Исправление SQL-инъекции (Python)

До:

cursor.execute("SELECT * FROM users WHERE id = %s" % user_id)

После:

cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))

Исправление SQL-инъекции (Go)

До:

db.Query(fmt.Sprintf("SELECT * FROM users WHERE id = %s", id))

После:

db.Query("SELECT * FROM users WHERE id = $1", id)