hermes-hub/agents/inbox/2026-08-30-A37-agent-isolation-and-guards.md
Hermes Team d897917ee7 docs(agents): задание A37 — изоляция агентов, защита учётных данных и разрушительных операций
Повод пришёл из разбора новостей: OpenAI описала инцидент, где
экспериментальные агенты использовали внутренний Artifactory как канал связи
между собой, обменивались найденными обходами и в итоге скомпрометировали
часть инфраструктуры Hugging Face. Вывод: deny internet != secure agent.

Задание опирается не на этот инцидент, а на наши собственные случаи, каждый
из которых проверен или произошёл в проекте:

- CORS стоял как allow_origins=["*"] с allow_credentials=True, а на localhost
  токен не требуется вовсе: любая открытая рядом страница получала полный
  снапшот со всеми аккаунтами и могла вызывать /api/action. Закрыто в
  c35bc48;
- агенты координируются через публичный репозиторий, и однажды работа ушла в
  main минуя ревью;
- агент Codex переключил ветку в каталоге, где работал ревьюер;
- учётные данные 24 аккаунтов лежат общей кучей, разделения по агентам нет;
- ревьюер удалил учётные данные grok-worker-1, проверяя кнопку удаления, и
  ничто этому не помешало;
- хаб открыт в домашнюю сеть поверх HTTP.

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

Выполнять после A34 и A35: пока нельзя подключить аккаунт и хаб не участвует
в вызовах Hermes, укреплять периметр преждевременно.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 22:03:15 +07:00

14 KiB
Raw Permalink Blame History

Задание A37: изоляция агентов, защита учётных данных и разрушительных операций

Дата поступления

2026-08-30

База

Ветка ревьюера review/a28-a31-fixes (ab2ee12).

git fetch origin --prune
git checkout -b antigravity/a37-isolation-guards origin/review/a28-a31-fixes

В main напрямую не пушить.

Порядок исполнения

Два прохода: Flash реализует, Pro проводит аудит. Пункт P0-6 написан для аудитора.

Выполнять после A34 и A35: пока нельзя подключить аккаунт и хаб не участвует в вызовах Hermes, укреплять периметр вокруг системы, которая ничем не управляет, преждевременно.


Задача

Владелец держит на трёх машинах 24 аккаунта, а работу ведут несколько автономных агентов. Изоляции между ними нет никакой, и это уже приводило к последствиям.

Повод пришёл извне: OpenAI официально описала инцидент, где экспериментальные агенты использовали внутренний Artifactory как канал связи между собой, обменивались найденными обходами, получили обходной доступ в интернет и в итоге скомпрометировали часть инфраструктуры Hugging Face. Вывод сформулирован там жёстко:

deny internet != secure agent

Разрешённый внутренний сервис становится proxy, доской объявлений, скрытым каналом и точкой опоры.

Наши собственные случаи — не гипотезы

Каждый проверен или произошёл в этом проекте:

  1. Любой сайт в соседней вкладке мог управлять хабом. CORS стоял как allow_origins=["*"] вместе с allow_credentials=True, а на 127.0.0.1 токен не требуется вовсе. Проверено запросом: страница со стороннего адреса получала 200 и полный снапшот со всеми аккаунтами. Закрыто ревьюером в c35bc48, но это тот самый класс, о котором говорит инцидент.

  2. Агенты координируются через общий канал — публичный репозиторий на GitHub. Они пишут ветки, читают чужие, и как минимум однажды работа ушла в main минуя ревью (зафиксировано в A23).

  3. Общее рабочее дерево. Агент Codex переключил ветку в каталоге, где в это же время работал ревьюер; коммиты чуть не легли в чужую ветку. Пришлось собирать их через временный индекс, чтобы не мешать.

  4. Учётные данные 24 аккаунтов лежат общей кучей в ~/.hermes/agy_profiles/, доступной любому процессу пользователя. Разделения по агентам нет.

  5. Ревьюер удалил учётные данные grok-worker-1, проверяя кнопку удаления на живом профиле. Ничто не помешало.

  6. Хаб открыт в домашнюю сеть поверх HTTP. Токен идёт по сети открытым текстом; почты аккаунтов — тоже, пока не сделан P0-4 из A31.

Что уже есть — не переделывать

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

agy_subprocess.build_safe_subprocess_env   очистка окружения подпроцесса
update_manager.ALLOWED_UPDATE_HOSTS        белый список хостов обновления
web/server.sanitize_snapshot               вычистка секретов из снапшота

P0-1. Граница рабочей области и разрушительные операции

Ни агент, ни модель, ни инструмент не должны удалять или перезаписывать данные за пределами разрешённой области, независимо от того, кто выполняет команду.

  1. Явная граница — каталог проекта плюс явно разрешённые пути. Всё остальное вне области.
  2. Классификация операций: удаление, рекурсивное удаление, массовое перемещение и перезапись, усечение. Проверять и вызовы Python (shutil.rmtree, os.remove, os.unlink), и командную строку (rm, rm -rf, Remove-Item, del), потому что агенты ходят обоими путями.
  3. Отказ объясняет причину и предлагает безопасную замену, а не просто запрещает.
  4. Безусловный запрет на каталоги учётных данных: ~/.hermes/agy_profiles/, ~/.ssh/, файлы auth.json, hub_settings.json. Удаление аккаунта делается только штатным действием delete_credentials с подтверждением — как раз потому, что удаление вручную уже происходило.
  5. Сухой прогон: показать, что будет удалено, до удаления.

P0-2. Разделение агентов

  1. У каждого агента свой рабочий каталог. Общее дерево уже приводило к переключению ветки под чужой работой. Отдельные клоны либо git worktree на агента.
  2. Свои учётные данные. Агенту нужны те аккаунты, с которыми он работает, а не все 24. Предложить схему разделения и обосновать; молча ничего не переносить — потеря учётных данных стоит владельцу повторного входа во все аккаунты.
  3. Свой след в журнале. Каждое действие с аккаунтами и конфигурацией записывается с указанием, кто его выполнил. Сейчас по журналу нельзя отличить действия ревьюера от действий агента.

P0-3. Сетевая граница самого хаба

  1. Белый список исходящих обращений. Хаб ходит к провайдерам, к API релизов и к локальным серверам — этот список конечен и должен быть явным. Образец есть: ALLOWED_UPDATE_HOSTS.
  2. CORS остаётся закрытым по умолчанию. Список источников — настройка web_api_allowed_origins. Возврат allow_origins=["*"] считать дефектом; нужен тест.
  3. Токен обязателен при небlocalhost-привязке — уже так, не ослаблять. Проверить, что сравнение осталось постоянного времени и в байтах.
  4. HTTP по сети — назвать риском в интерфейсе. Владелец должен видеть, что при сетевой привязке поверх HTTP токен и почты идут открытым текстом. Не запрещать, а сказать прямо и предложить туннель или VPN.

P0-4. Журнал, по которому можно расследовать

После инцидента вроде описанного нужен ответ на вопрос «кто, что и когда».

Записывать: кто выполнил, какое действие, над каким профилем и ролью, результат, время. Секреты в журнал не попадают — тест на это уже есть для снапшота, распространить на журнал.

P0-5. Проверка исполнением

  1. Попытка удалить файл вне рабочей области — отказ с причиной; проверено.
  2. Попытка удалить каталог учётных данных — отказ; проверено.
  3. Обращение к хосту вне белого списка — отказ; проверено.
  4. Запрос с чужого Origin — заголовков CORS нет; проверено запросом.
  5. Работа хаба при всех включённых ограничениях не деградирует: маршрутизация, обновление, обнаружение моделей работают.

Пункт 5 обязателен: защита, ломающая продукт, хуже её отсутствия.

P0-6. Аудит вторым проходом

  1. Ложное чувство защиты. Проверить, что ограничения нельзя обойти очевидным способом — например, относительным путём или символической ссылкой за пределы области.
  2. Отказ не должен ронять хаб. Сработавшая защита — это отказ операции, а не падение процесса.
  3. Секреты в журнале и в сообщениях об отказе — искать целенаправленно.
  4. Запустить с ограничениями и поработать, а не только прогнать тесты.
  5. Побочные изменения объяснить.
  6. Пропущенный пункт назвать пропущенным.

Ограничения

  • Не ломать работу агентов ради строгости: они должны продолжать работать в своих каталогах.
  • Учётные данные не переносить и не удалять без явного согласия владельца.
  • Зона: новый слой безопасности, web/server.py, журнал, тесты. Веб-клиент — A34, определение роли — A35, конвейер — A36.
  • Правило честности без исключений.
  • Тег v0.1.1 не создавать.

Критерии приёмки

  1. Ветка в origin от review/a28-a31-fixes, git status чист.
  2. Разрушительная операция вне рабочей области отклоняется с причиной; проверено исполнением.
  3. Каталоги учётных данных защищены безусловно; удаление аккаунта возможно только штатным действием.
  4. Есть сухой прогон, показывающий последствия до выполнения.
  5. Агенты разведены по рабочим каталогам; схема разделения учётных данных предложена и обоснована, ничего не перенесено без согласия.
  6. Белый список исходящих обращений работает; обращение вне списка отклоняется.
  7. CORS закрыт по умолчанию, есть тест на возврат allow_origins=["*"].
  8. Риск HTTP по сети назван в интерфейсе.
  9. В журнале видно, кто выполнил действие; секретов в нём нет.
  10. Хаб при включённых ограничениях полностью работоспособен; проверено.
  11. ruff check . чисто; релизный гейт не ухудшен.
  12. Отчёт: START_HEAD, FINAL_HEAD, origin/main, git status, X passed / Y skipped / Z failed. На ветке ревьюера сейчас 475 passed, 2 skipped.

Главное

У владельца на трёх машинах лежат ключи от 24 аккаунтов, а работают там автономные агенты без изоляции друг от друга. Пока не было потерь, но все предпосылки уже сработали хотя бы раз: и удаление учётных данных, и работа в чужом дереве, и открытый доступ к хабу из браузера.

Порядок сдачи

Передать точный FINAL_COMMIT_SHA.