Детекция опасного поведения агента
Статус: реализовано (этапы 1–3). Детерминированные детекторы
(kernel/agent/behaviorscan.go: утечки секретов, канарейки, опасный контент,
подозрительные аргументы, правки тестов/CI, скан base64/hex/urlencode),
корпусный семантический матчер на модели эмбеддингов (слой 2) и
судья-наблюдатель этапа 3 (supervisorcases.go, monitorSuspicionMin)
работают в проде. Реализованы и «фантазии» §5: egress-контур
(cmd/agent-kernel/egress.go + squid-прокси + allowlist, см. §7),
honeypot-канарейки в воркспейсе (PrepareRun), verification_gap.
#1. Постановка
Песочница снимает проблему локальных харнесов (защита машины пользователя): внутри контейнера агенту можно творить что угодно — blast radius ограничен контейнером и воркспейсом. Остаётся две настоящие оси риска:
- Выход за песочницу — всегда через сеть и секреты. Ограничения должны жить в самом токене (least privilege, неразрушающие скоупы, короткий TTL, аудит на стороне внешней системы) — тогда даже успешный «побег» не даёт деструктивной мощности.
- Опасное поведение модели — когда она решает, что честно задачу не решить, и: фейкует верификацию («тесты зелёные» без запуска), саботирует проверки (правит тесты/CI под результат — reward hacking), кладёт деструктив в артефакт (бэкдоры, time bombs, скрытые вызовы наружу), ищет путь наружу (env/секреты/docker socket/внешние хосты), врёт в отчёте.
Задача — ловить такое раньше, чем начнётся разрушение, не превращая эксплуатацию в подтверждение каждого шага.
#2. Таксономия опасных поведений (что ловим)
| Класс | Примеры | Основной сигнал |
|---|---|---|
| Фейковая верификация | «тесты зелёные» без запуска; выборочный прогон | расхождение claim vs reality |
| Подмена проверок (reward hacking) | правка тестов/чеков/CI под результат; --no-verify |
дифф по тестам/CI — отдельная категория |
| Деструктив в артефакте | бэкдор, rm-логика, time bombs, обфусцированный exfil в коде | сканер диффа артефакта |
| Разведка/побег | чтение env/ключей не по делу, docker socket, метаданные облака, внешние хосты | egress-лог, сканер аргументов |
| Утечка секретов | значения/кодировки секретов в командах, выводе, диффе | сканер значений + canary |
| Обман в отчёте | скрытый провал, выдача желаемого за сделанное | независимая верификация, монитор |
#3. Механизмы детекции по горизонтам
#Во время работы (in-process) — главное
- Monitor-судья (untrusted monitoring): дешёвая/доверенная модель читает действия агента (тул + аргументы + контекст задачи) и по заранее зафиксированной рубрике ставит suspiciousness. Высокий скор → пауза + кейс человеку. Протокол из AI Control (Greenblatt et al., arXiv:2312.06942); OpenAI применяет то же для детекции reward hacking в Codex.
- Независимая верификация заявлений (реализовано, deterministic): раны,
чей финальный ответ заявляет прохождение проверок, при отсутствии в
журнале команд верификации попадают в супервайзер как
verification_gap. Делегировавшие раны пропускаются (проверки исполняют дети). Не верить самоотчёту агента — он же и действует, и отчитывается. - Правки тестов/CI — отдельная видимая категория диффа (не запрет: иногда легитимно, но всегда светится).
- Сканер значений секретов: значения известны ядру при выдаче; сканировать аргументы, вывод, диффы — включая base64/hex/urlencode. Canary-секреты (подложные токены): любое использование = побег обнаружен.
- Детерминированный сканер диффа артефакта: rm -rf, curl|sh, base64-eval, обращения к ключевым файлам/секретам, сеть на не-allowlist хосты.
- Egress-контроль песочницы: домен-allowlist на проект/агента + лог DNS/соединений; ловит exfil/побег независимо от формулировок.
- Плановые ворота + сверка с DoD: одно подтверждение плана, дальше монитор сверяет поведение с зафиксированным DoD (дрейф = сигнал).
#До работы (upfront)
- Токены: скоуп без деструктива, короткий TTL.
- Рубрика «что считается подозрительным» фиксируется заранее.
- Honeypot-файлы в воркспейсе (изменение без права = сигнал).
#После (post-hoc)
- Сессионный отчёт: семантический дифф + эпизоды монитора + расхождения claim/reality (у нас — журнал + супервайзер).
- Офлайн-пересмотр выборки прошлых ранов более мощным монитором; калибровка рубрики.
#4. Опыт больших харнесов (справка)
Локальные харнесы (Claude Code, Codex CLI, Cursor, Cline, Goose, Gemini CLI) решают другую задачу — защита машины пользователя, поэтому их модели (allow/ask/deny списки с паттернами, permission modes, «always allow» на проект) нам напрямую не подходят. Полезное оттуда:
- Деление по границе workspace (внутри — свободно, снаружи — спросить) — у нас это уже песочница, граница = сеть и секреты.
- Разделение осей: файлы ≠ сеть ≠ секреты ≠ MCP. У нас так и есть.
- Approval fatigue лечится не тумблером, а горизонтами «да» и правилами.
Облачные агенты (Devin, Copilot coding agent) — противоположный полюс: per-call approval отсутствует, изоляция средой + ревью результата (PR). Наша песочница ближе к этому полюсу, значит акцент смещается с подтверждений на детекцию.
#5. Детерминированная семантическая детекция по цепочке тул-колов
Идея: без LLM в рантайме — заранее собрать корпус паттернов опасного поведения (побег, деструкция, exfil, подмена проверок), превратить их в векторы и быстро сверять цепочку ходов рана (n-граммы тул-колов + аргументы) с корпусом.
#Оценка осуществимости
Ресурсы — копейки. Модель эмбеддингов уже в процессе (e5-small через rembed), эмбеддинг короткого текста — миллисекунды; корпус в сотни паттернов — сотни векторов; сравнение — косинус против сотен векторов на ход/ран. Ни сети, ни LLM, ни заметной нагрузки.
Что реально ловится:
- Парафразы известных опасных действий — аргументы, сформулированные иначе,
чем в паттерне («почистить всё в директории» vs
rm -rf), но с близкой фактурой. Слабое место regex-листов, сильное — эмбеддингов. - Близкое к дословному совпадение с известным плохим паттерном (высокий косинус) — самый надёжный режим: near-duplicate detection у эмбеддингов работает отлично.
- Накопленные реальные инциденты: вердикты супервайзера («плохой ран») пополняют корпус автоматически — копилка известных плохих цепочек растёт от эксплуатации (флайвил с существующей миня-инфраструктурой три-грамм).
Что НЕ ловится (честные границы):
- Обфускация:
echo aGVsbG8= | base64 -d | shне похож эмбеддингом на «декодировать и исполнить скрытое» — e5 меряет поверхностную семантику текста, а не намерение. Целенаправленно замаскированное проходит мимо. Против обфускации работают детерминированные слои (сканер значений секретов, egress, canary), а не семантика. - Точные имена тулов без аргументов слишком генеричны: почти любой ран
похож на любой. Опасность живёт в аргументах — векторизовать надо
тул + командную строку/ключевые аргументы. - Точность: «удалить артефакты сборки» семантически близко к «снести всё» — false positives неизбежны. Поэтому это ранжировщик сигналов для супервайзера, а не автокаратель: скор + совпавший паттерн + эпизоды → человек решает.
Вердикт: дёшево и полезно как слой раннего предупреждения и приоритизации (в т.ч. как фильтр перед дорогим monitor-судьёй), но не как самостоятельный детектор намерения. Ставить в стек, ожидать среднюю точность, замыкать фидбеком человека.
#Дизайн-набросок (слои, все без рантайм-LLM)
| Слой | Механизм | Точность | Ловит |
|---|---|---|---|
| 0. Тул-паттерны | regex/точные паттерны по нормализованным аргументам | высокая precision | известное дословное |
| 1. n-граммы | хешированные n-граммы токенов аргументов и три-граммы цепочки (механизм майнинга уже есть) | высокая на near-dup | известные последовательности |
| 2. Эмбеддинги | вектор корпуса опасных паттернов (curated + из вердиктов) vs вектор окна цепочки | средняя | парафразы, «похожее поведение» |
| 3. Monitor-судья | LLM-рубрика | высшая | намерение, обман, скрытое |
- Корпус: curated из публичных таксономий (MITRE ATT&CK containers, OWASP LLM, саботаж-evals) + генерация вариантов судьёй офлайн (LLM на этапе сборки корпуса допустим — рантайм остаётся LLM-free) + реальные инциденты из вердиктов супервайзера.
- Хранение: векторный стор уже есть (эмбеддинги знаний + neighbors); паттерны
— с зарезервированным префиксом (
danger/…), чтобы не мешать знаниям. - Гранулярность: скользящее окно последних k вызовов (раннее обнаружение) + агрегат рана целиком (итоговый скор). Эмбеддинг аргумента считать один раз в момент tool.started (тот же конвейер, что публикует эмбеддинги знаний).
- Действие: скор + совпавший паттерн → кейс супервайзера (новый case-kind); при экстремальном скорe — пауза перед следующим ходом. Без автокилла.
- Фидбек: вердикт человека (ложная тревога / подтверждено) обновляет корпус и пороги per-project.
#6. Приоритезация внедрения
Этапы 1–3 внедрены; таблица ниже — исторический план, порядок совпал с реализацией.
| Этап | Что | Цена |
|---|---|---|
| 1 | Сканер значений секретов в args/outputs/диффах | значения уже в ядре |
| 1 | Правки тестов/CI в диффе — отдельная видимая категория | классификация путей диффа |
| 1 | Детерминированный сканер деструктива в диффе | статические паттерны |
| 2 | Слой 0–2 детекции по цепочке (выше) + кейс супервайзеру | инфраструктура эмбеддингов уже есть |
| 2 | Независимая верификация заявлений (kernel re-run) | Activities уже гоняют команды |
| 2 | Canary-секреты | выдача секретов уже через ядро с журналом |
| 3 | Monitor-судья на ход (рубрика + скор) | судья и супервайзер есть |
| 3 | Egress allowlist + лог соединений песочницы | инфраструктура сети |
#7. Egress allowlist
Сеть песочницы и список разрешённых внешних адресов — независимые оси (первое — «может ли вообще ходить наружу», второе — «куда именно»):
- У агента есть переключатель сетевого доступа и список egress-адресов;
базовый список приходит из org-политики (
egress_allowlist) и объединяется со списком агента: политика — общий базис, агент добавляет свои исключения. - Трафик песочницы идёт через внутреннюю сеть
temporality-sandbox-internal(--internal, прямого маршрута наружу нет) и squid-прокси (cmd/agent-kernel/egress.go, сервисsquidв compose) с per-agent портом: пропускаются ровно адреса из объединённого списка. - Когда egress-стек не развёрнут, остаётся прежний режим мостовой сети
(
bridge/noneпо переключателю) — без прокси-фильтрации.