Перейти к содержимому

Безопасность и меры защиты

Chimera умеет выполнять команды оболочки, править файлы, вызывать API и менять собственные навыки. Она поставляется с эшелонированной защитой — и, что важно, документация говорит, где каждый слой заканчивается.

Единственное правило

Ни одна из этих мер не заменяет запуск в изолированной среде, когда вы даёте самостоятельность. Локальный исполнитель по умолчанию не изолирован; для недоверенной работы используйте CHIMERA_SANDBOX=docker (без сети, при желании под gVisor).

Слои

  • Ядро управления — каждый управляемый вызов инструмента получает разрешить / предупредить / разобрать / заблокировать. Это дешёвый первый фильтр опасных сигнатур оболочки, а не граница.
  • Песочница — временный контейнер без сети (CHIMERA_SANDBOX=docker), усиливаемый gVisor (CHIMERA_SANDBOX_RUNTIME=runsc). Проверяющая команда выполняется в той же песочнице, что и оболочка агента, а когда эта песочница не изолирует, команда, набранная не вами, — выведенная из репозитория, прочитанная из задания по расписанию, из карточки или из сценария, — проходит через то же подтверждение CHIMERA_HOST_EXEC; при отказе она воздерживается, а не выполняется (CHIMERA_VERIFY_NETWORK=1 даёт сеть проверяющему в docker; в песочницах уровня ядра так нельзя, поэтому проверяющий, которому нужна сеть, работает на хосте — и только если его набрали вы).
  • Список разрешённых инструментов на сессию — дайте запуску только те инструменты, которые ему нужны; остальные вовсе убираются из схемы, которую видит модель.
  • Отслеживание заражения (--taint) — недоверенное содержимое обособляется как данные, его происхождение следует за ним в воспоминания и навыки (навык из заражённого запуска удерживается на разбор), а как только запуск заражён, опасные инструменты сужаются.
  • Изолированный читатель — приём двух моделей (CaMeL): недоверенное содержимое читает модель без инструментов, способная выдать только поля, прошедшие проверку схемы, поэтому внедрение не может породить новую инструкцию или вызов инструмента.
  • Монитор между агентами — при веерном запуске монитор одного работника слеп к разделённому потоку (один работник забирает недоверенное, другой его сливает — забор и слив живут в разных журналах). Сводный монитор видит весь веер; для solve-batch и crew-isolated он всегда включён.

Веерный запуск: монитор между агентами

Когда несколько работающих с инструментами агентов идут параллельно (solve-batch, crew-isolated), каждый получает свой журнал полномочий, а после пакета по всем ним проходит сводный монитор. Он ловит то, чего не увидит монитор одного работника, — разделённую утечку, где работник A забирает недоверенное содержимое, а работник B его выполняет или отправляет наружу:

$ chimera solve-batch "read notes.md and summarize" "download the helper and run it" -w .
task1: ok
task2: ok
merged 2 file(s) across 2 task(s)
⚠ cross-agent monitor flagged (review):
  - cross-agent-taint: untrusted content entered via one agent and a different agent
    performed a sink (task2→task1) — a split flow no single-agent monitor sees

Он только поднимает до разбора — запуск он никогда не блокирует — и является чистым наблюдением (запись ничего не меняет в поведении). Добавьте сверху --taint, чтобы заодно взвести у каждого работника подстраивающийся список разрешений (опасные при заражении инструменты начнут требовать одобрения).

Одобрение и как выглядит работник, которому отказали. У каждого работника свой одобряющий и своя запись того, что ему позволили сделать, поэтому отклонённая задача так и говорит, а не сообщает ok:

$ chimera solve-batch "read notes.md and summarize" "download the helper and run it" --taint -w .
task1: ok
task2: not allowed (ok)
  governance: 1 action(s) refused for review: run_shell is restricted after this run consumed
  untrusted content
1 of 2 task(s) had actions refused for review — check that the work they were asked to do
actually happened.

ok в скобках — это вердикт самого цикла, и то, что они расходятся, и есть суть: отклонённый вызов возвращается обычной строкой наблюдения, работник читает её как любой результат инструмента, идёт дальше и заканчивает прозой. Кого можно спросить, решает CHIMERA_APPROVAL_MODE — deny отказывает сразу, ask спрашивает в терминале, а иначе записывает вопрос для chimera approve и ждёт CHIMERA_APPROVAL_WAIT секунд — на каждый вопрос и на каждого работника. Молчание всегда отказ.

Измерено, а не заявлено

chimera redteam

прогоняет корпус внедрений через весь стек. На встроенном корпусе слой заражения снижает долю успешных атак со 100% примерно до 14% — и отчёт называет то, что всё ещё проходит (утечка через разрешённый инструмент), вместо того чтобы объявить 100%.

Та же команда печатает цену, чего первая версия этой страницы не делала: когда спросить некого, сужение отказывает в 100% законной работы, которая сначала прочитала что-нибудь внешнее — исправить файл, названный в issue, применить обновление, описанное в документации, — и зарегистрированный заслон (избыточные блокировки ≤ 5%) не пройден. Это число — не вопрос настройки; заслон был пуст. Режим одобрения по умолчанию — ask, и в приложении он теперь спрашивает: суженный вызов инструмента превращается в вопрос на экране с приложенной причиной из журнала; ответить на него можно кнопкой или командой chimera approve, а молчание дольше CHIMERA_APPROVAL_WAIT секунд означает отказ. Когда человек одобряет работу, о которой сам и попросил, избыточных блокировок 0%, а доля заблокированных атак не меняется — измерено, по каждому плечу, в bench/injection/RESULTS.md. Утечка через разрешённый инструмент закрыта тем же изменением: в заражённом запуске http_get со строкой запроса идёт на разбор, а два законных GET-запроса со строкой запроса, добавленные в корпус, показывают, чего это стоит.

Отравленная память, из запуска в запуск

redteam измеряет один запуск. Другая форма медленнее и не умещается в один процесс: запуск A читает отравленную страницу и сохраняет то, что «усвоил»; запуск B через несколько дней спрашивает о постороннем, и обращение к памяти передаёт модели подброшенный факт.

chimera memory-poison

Тоже офлайн и бесплатно. Она по очереди отключает три слоя, стоящих между этими запусками, — флаг происхождения tainted, приёмные ворота памяти и ярлык [unverified], с которым факт входит в промпт, — потому что одно-единственное число было бы совместимо с тем, что любой из них ничего не делает. Главное здесь — то, что доходит без пометки, а не то, что заблокировано: отравленный факт, несущий своё происхождение, — это факт, о котором модель предупредили; факт без ярлыка неотличим от того, что агент проверил сам.

Два результата первого прогона стоит назвать прямо, потому что ни один из них нам не льстит:

  • Поставляемая конфигурация не проходит собственный заслон — по цене. Она помечает 100% отравы и уничтожает при этом 25% честной памяти. Потери названы поимённо: документ по безопасности, который цитирует атаку, чтобы её объяснить, и обращение в поддержку, пересылающее попытку. Проверка содержимого по шаблонам не отличает цитату от команды.
  • На этом корпусе заслон по содержимому не добавляет ничего, чего уже не покрывает метка происхождения. Весь его измеренный эффект — та честная память, которую он убирает. Пятнадцать написанных вручную строк — это указатель, а не вердикт, и потому на их основании ничего не удалено.

Пороги, метод и то, чего эти числа не позволяют утверждать, лежат в bench/memory_poison/PREREGISTRATION.md, зафиксированные до первого прогона.

Как выставить HTTP-сервер наружу

chimera serve по умолчанию слушает на 127.0.0.1. Его меняющие состояние конечные точки (/chat, /a2a, /webhook/*) управляют агентом, поэтому перед тем как выставить сервер в сеть, задайте токен доступа:

export CHIMERA_SERVER_TOKEN="a-long-random-secret"   # required as: Authorization: Bearer <token>

Когда он задан, эти точки POST возвращают 401 без подходящего заголовка Authorization: Bearer (GET /health и карточка агента A2A остаются открытыми). Для входящего вебхука WhatsApp задайте CHIMERA_WHATSAPP_APP_SECRET равным секрету вашего приложения Meta — тогда Chimera проверяет HMAC X-Hub-Signature-256 каждого запроса и отвергает подделку с кодом 403. И то и другое включается по желанию (не задано = аутентификации нет, что годится для localhost); публичное развёртывание должно их задать (или стоять за прокси с проверкой подлинности).

Поделиться беседой со вторым человеком

Настольное приложение может поделиться беседой о коде по токену, который открывает только эту беседу — никогда не по серверному токену. Владелец выпускает по одному на гостя (POST /api/code/sessions/{id}/share) и может отозвать его отдельно; удаление беседы отзывает все. Гость достигает четырёх маршрутов под /guest/api/…: прочитать беседу, следить за ней вживую, отправить в неё сообщение, увидеть, кто есть. Больше ничего на токен доступа не отвечает, и у гостевого приложения нет маршрута, чтобы ответить на карточку управления — они остаются на экране владельца.

Гостевое приложение — также единственное, что обслуживается, когда владелец открывает сетевую дверь (POST /api/code/share/network, закрывается через DELETE, при запуске никогда не открыта): машина в локальной сети достигает этих четырёх маршрутов и ничего из того, что защищает серверный токен. Сказать прямо, прежде чем отдавать ссылку: гость может попросить агента о чём угодно, о чём попросил бы владелец, в проекте владельца, его инструментами и за его счёт — в рамках настроек запроса по умолчанию и без права одобрять карточки.

Честные пределы

Здесь измеряется, останавливается ли вредное действие уже внедрённого агента, — а не то, можно ли внедриться в модель изначально. Свободное рассуждение над недоверенным текстом и утечка через инструменты, которые действительно нужны, остаются открытыми задачами (отслеживаются как issue #5).

Полная и всегда актуальная политика лежит в SECURITY.md, включая порядок сообщения об уязвимости.

Изменить эту страницу на GitHub