Модель угроз¶
Эта страница выводит на поверхность принятый проектный документ ограниченного
контекста 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. Активы (что мы защищаем)¶
- Авторизация вызова инструментов — какие инструменты и с какими аргументами агент может вызывать.
- Чувствительные данные в
messages/state(PII, секреты) — против эксфильтрации. - Целостность инструкций агента — устойчивость к prompt injection, включая непрямую инъекцию через содержимое загруженных URL и результаты инструментов.
- Целостность общего состояния — против отравления через
STATE_DELTA. - Доступность сервиса агента — против DoS (чрезмерно большое состояние / патчи, медленные потоки).
- Доказуемость нетронутости журнала аудита (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. Дальнейшие шаги¶
- Определить домен
agate-proxy: агрегатSession/Run, не зависящие от протокола объекты-значенияInspectedEventи объект-значениеVerdict. - Определить порты приложения:
PolicyPort(источник вердикта), приёмник аудита и клиент вышестоящего агента. - Построить адаптер AG-UI: SSE-кодек (инкрементальный, сохраняющий порядок),
валидация
RunAgentInput, трансляция событий. - Презентация HTTP/SSE (axum/hyper), терминация TLS, проводка запроса / ответа.
- Стенд для оценки: накладные расходы по задержке / пропускной способности встроенной инспекции.