Перейти к содержанию

Модель угроз

Эта страница выводит на поверхность принятый проектный документ ограниченного контекста agate-proxy — плоскости данных, инспектирующей трафик LLM-агента. Он определяет, что защищает прокси, от кого, где он располагается и единственный шов принятия решений (событие → вердикт), к которому подключаются контексты аудита и политик.

Перевод канонической записи

Канонический источник истины — английский и находится в репозитории (docs/design/agate-proxy-threat-model.md). Ниже включён его русский перевод (docs/design/agate-proxy-threat-model.ru.md). Перевод поддерживается в синхронизации с английским оригиналом через CI-страж дрейфа (scripts/check-i18n.sh): если английский документ меняется, проверка падает, пока перевод не обновят.

Кратко

  • Режим: гибридный встроенный (inline) — превентивный на «ноге» запроса, потоковая инспекция на «ноге» ответа.
  • TLS: терминируется на прокси (необходимо для инспекции открытого текста).
  • Шов: каждое инспектированное событие даёт вердикт (Allow / Deny / Transform / Buffer / Terminate); agate-policy его вычисляет, agate-audit его записывает.
flowchart LR
    fe["Фронтенд<br/>(недоверенный)"]
    proxy["agate-proxy<br/>точка TLS"]
    agent["Агент (AG2)"]
    llm["LLM-провайдер"]
    tools["Инструменты / MCP-серверы"]
    fe <-->|"AG-UI (инспектируется)"| proxy
    proxy <--> agent
    agent <--> llm
    agent <--> tools
    classDef boundary fill:#0b7285,stroke:#0b7285,color:#fff;
    class proxy boundary;

agate-proxy — Модель угроз и топология развёртывания

Статус: принято (первоначальный дизайн) Область: ограниченный контекст agate-proxy — плоскость данных, инспектирующая трафик LLM-агента. Этот документ определяет, что защищает agate-proxy, от кого, где он располагается и единственный шов принятия решений (событие → вердикт), к которому подключаются контексты аудита и политик.


1. Контекст

Agate — это шлюз безопасности для LLM-агентов, говорящих по протоколу AG-UI (где AG2 выступает эталонным фреймворком агентов). agate-proxy — это обратный прокси в пути запроса. Он добавляет аутентификацию, валидацию входных данных, инспекцию выходных данных и точку принятия решений — не меняя код агента.

Ядро не зависит от протокола; AG-UI — это первый транспортный адаптер. Второй адаптер (агент ↔ API LLM-провайдера) можно добавить позже, не трогая ядро домена инспекции.


2. Поверхность атаки, вытекающая из протокола

Эти факты об AG-UI определяют модель угроз. AG-UI — это HTTP POST с телом JSON RunAgentInput (клиент → агент) плюс поток событий (text/event-stream, SSE) в ответе (агент → клиент). 34 типа событий, охватывающих жизненный цикл, потоковую передачу текста, вызовы инструментов и управление состоянием.

Чего протокол не предоставляет — и что, следовательно, должен добавить прокси:

Пробел в AG-UI Последствие Прокси должен
Нет аутентификации / авторизации Любой, кто достигает эндпойнта, может управлять агентом Применять authn/authz на POST до начала стриминга
Нетипизированный any повсюду (state, forwardedProps, context.value, parameters инструментов, RAW, CUSTOM) Путаница схем, чрезмерно большие полезные нагрузки, инъекции Ограничивать размеры; проверять по схеме там, где она есть; считать непрозрачные поля недоверенными
STATE_DELTA = неограниченный JSON Patch (RFC 6902) Отравление состояния; DoS через число операций / глубину / размер значений Валидировать и ограничивать операции патча
Нет порядковых номеров, нет подписи на каждое событие, необязательный timestamp Повтор (replay); инъекция поддельных событий при компрометации одной из «ног» Полагаться на упорядоченный транспорт (SSE по одному соединению); добавлять собственную упорядоченность / идемпотентность там, где нужно
Аргументы вызова инструментов передаются как конкатенированные фрагменты JSON-строки (TOOL_CALL_ARGS между START / END) Решение нельзя принять по одному кадру Буферизовать полный вызов инструмента до вынесения вердикта
Сообщения user могут встраивать удалённые URL (источники изображений / документов) Поверхность SSRF / загрузки контента Проверять входной контент с URL-типами
encryptedValue, REASONING_ENCRYPTED_VALUE, RAW, CUSTOM непрозрачны Невозможно инспектировать Политика «пропустить-или-отбросить»; никогда не доверять
Долгоживущие потоки, нет ограничений размера Истощение ресурсов, slowloris Бюджеты времени / размера / частоты на каждый прогон и на каждое соединение
Необязательный бинарный транспортный вариант на protobuf Путаница парсеров Согласовывать / ограничивать принимаемые кодировки

Сам архитектурный документ AG-UI предвосхищает необязательный middlebox «Secure Proxy», но ничего не говорит о том, что он должен обеспечивать — и этот пробел есть вклад данной работы.


3. Активы (что мы защищаем)

  1. Авторизация вызова инструментов — какие инструменты и с какими аргументами агент может вызывать.
  2. Чувствительные данные в messages / state (PII, секреты) — против эксфильтрации.
  3. Целостность инструкций агента — устойчивость к prompt injection, включая непрямую инъекцию через содержимое загруженных URL и результаты инструментов.
  4. Целостность общего состояния — против отравления через STATE_DELTA.
  5. Доступность сервиса агента — против DoS (чрезмерно большое состояние / патчи, медленные потоки).
  6. Доказуемость нетронутости журнала аудита (tamper-evidence) — уже принадлежит agate-audit; прокси питает его, но не реализует заново.

4. Границы доверия и действующие лица

Путь: фронтенд ↔ agate-proxy ↔ приложение-агент (AG2) ↔ LLM-провайдер ↔ инструменты / MCP-серверы.

Прокси сидит прежде всего на границе фронтенд ↔ агент (AG-UI). Всё на стороне клиента от прокси и всё, что испускает агент / LLM, является недоверенным входом, который надо инспектировать.

Действующие лица-угрозы:

  • Вредоносный / скомпрометированный клиент (фронтенд) — формирует RunAgentInput: чрезмерно большое state, вредоносные параметры инструментов, SSRF-URL, prompt injection в сообщениях user.
  • Вредоносный / скомпрометированный агент или бэкенд LLM — испускает враждебные события: эксфильтрация через вызовы инструментов, отравление состояния через STATE_DELTA, вредоносный контент, неавторизованные вызовы инструментов.
  • Скомпрометированный инструмент / MCP-сервер — когда результаты инструментов проксируются обратно.
  • Привилегированный оператор / инсайдер — подделка журналов (смягчается agate-audit, вне области рассмотрения здесь).
  • Непрямая prompt injection — данные, подтянутые через URL-источники или результаты инструментов, которые манипулируют агентом.

Вне области рассмотрения (обрабатывается в другом месте или инфраструктурой): MitM на транспортном уровне (TLS), внутренняя логика самого агента, безопасность LLM-провайдера.


5. Перечисление угроз

Адаптированный STRIDE, привязанный к специфике AG-UI.

  • Spoofing (подмена) — нет аутентификации на уровне протокола → выдача себя за пользователя / агента. Смягчение: authn на POST; прокси — точка терминации TLS (§6).
  • Tampering (подделка) — поддельные / изменённые события на скомпрометированной «ноге»; отравление через STATE_DELTA. Смягчение: упорядоченный транспорт по одному соединению; ограниченные, валидированные патчи; вердикт на событиях, меняющих состояние.
  • Repudiation (отказ от авторства) — отрицание действия. Смягчение: каждое инспектированное событие + вердикт записываются в журнал прозрачности аудита.
  • Information disclosure (раскрытие информации) — эксфильтрация PII / секретов через аргументы вызова инструментов или текстовый контент; SSRF через URL-источники. Смягчение: буферизация и инспекция вызовов инструментов; редактирование текстового контента; проверка URL.
  • Denial of service (отказ в обслуживании) — чрезмерно большое state, неограниченный JSON Patch, slowloris на потоке SSE. Смягчение: бюджеты размера / времени / частоты; ранний отказ на «ноге» запроса.
  • Elevation of privilege (повышение привилегий) — вызов инструментов сверх гранта клиента. Смягчение: вердикт allow/deny на вызов инструмента на шве (это заполняет политика).

6. Топология развёртывания (решения)

6.1 Размещение — ядро без привязки к протоколу, адаптер AG-UI первым

Ядро инспекции не зависит от протокола; проводной протокол входит через адаптер, который транслирует проводные события в доменные. Адаптер AG-UI строится первым (основная позиция: фронтенд ↔ агент). Второй адаптер для трафика агент ↔ LLM можно добавить позже без изменения ядра — это конкретное доказательство того, что «AG-UI — лишь один из адаптеров».

6.2 Режим — гибридный встроенный (inline)

Прокси встроен (в пути запроса, способен блокировать / преобразовывать) и работает в две фазы:

  • «Нога» запроса (превентивная): полный RunAgentInput доступен до пересылки, поэтому валидация / authz / ограничения размера дёшевы и решающи — отклоняем до того, как агент вообще запустится.
  • «Нога» ответа (потоковая инспекция): поток событий SSE парсится инкрементально; прокси может завершить поток, заменить его на RUN_ERROR или отредактировать / преобразовать контент (например, TEXT_MESSAGE_CONTENT). Вызовы инструментов буферизуются между TOOL_CALL_START и TOOL_CALL_END, чтобы вердикт видел полные аргументы.

Поведение fail-open против fail-closed по политике настраивается для каждого развёртывания. Отсюда же берётся глава об оценке: добавленная задержка и стоимость пропускной способности встроенной потоковой инспекции.

(Отклонено: только превентивный inline — не может хорошо инспектировать потоковый вывод; детективный отвод (tap) — нулевая задержка, но ничего не может предотвратить, поэтому не удовлетворяет активам 1–4. Гибрид сохраняет предотвращение, ограничивая стоимость.)

6.3 TLS — терминируется на прокси

agate-proxy — это точка терминации TLS, к которой подключается фронтенд. Терминация TLS необходима для встроенной инспекции контента. (Внешний балансировщик нагрузки всё ещё может стоять перед ним, но прокси должен видеть открытый текст, чтобы инспектировать.)


7. Шов «событие → вердикт»

Инспекция производит на каждое событие (или на каждую буферизованную логическую единицу) вердикт:

Allow                  // переслать без изменений
Deny(reason)           // блокировать; на «ноге» ответа выдать как RUN_ERROR
Transform(replacement) // переслать изменённое событие (например, отредактированный контент)
Buffer                 // нужно больше кадров перед решением (например, посреди вызова инструмента)
Terminate(reason)      // завершить прогон / поток

Этот единственный шов — место, куда подключаются два контекста:

  • agate-audit — записывает (event, verdict) в журнал прозрачности.
  • agate-policyвычисляет вердикт (PolicyPort).

Для первой вехи agate-proxy поставляется с тривиальным адаптером политики allow-all за PolicyPort; agate-policy заменит его позже без изменения плоскости данных.


8. Вне области рассмотрения (пока)

  • Адаптер агент ↔ LLM (заложен в дизайн, но ещё не реализован).
  • Содержимое политик (allowlist'ы, правила редактирования PII, эвристики против инъекций) — принадлежит agate-policy.
  • Внешнее закрепление (anchoring) контрольных точек аудита — принадлежит agate-audit.
  • Подделка журналов на стороне оператора — смягчается дизайном контекста аудита.

9. Дальнейшие шаги

  1. Определить домен agate-proxy: агрегат Session / Run, не зависящие от протокола объекты-значения InspectedEvent и объект-значение Verdict.
  2. Определить порты приложения: PolicyPort (источник вердикта), приёмник аудита и клиент вышестоящего агента.
  3. Построить адаптер AG-UI: SSE-кодек (инкрементальный, сохраняющий порядок), валидация RunAgentInput, трансляция событий.
  4. Презентация HTTP/SSE (axum/hyper), терминация TLS, проводка запроса / ответа.
  5. Стенд для оценки: накладные расходы по задержке / пропускной способности встроенной инспекции.