Безопасность
Hermes Agent спроектирован с многоуровневой моделью безопасности (defense-in-depth). На этой странице рассматриваются все границы безопасности — от подтверждения команд до изоляции контейнеров и авторизации пользователей на платформах обмена сообщениями.
Обзор
Модель безопасности включает семь уровней:
-
Авторизация пользователей — кто может общаться с агентом (белые списки, DM-сопряжение)
-
Подтверждение опасных команд — human-in-the-loop для деструктивных операций
-
Изоляция контейнеров — Docker/Singularity/Modal-песочницы с усиленными настройками
-
Фильтрация учётных данных MCP — изоляция переменных окружения для подпроцессов MCP
-
Сканирование контекстных файлов — обнаружение prompt-инъекций в файлах проекта
-
Изоляция между сессиями — сессии не могут получить доступ к данным или состоянию друг друга; пути хранения задач cron защищены от path traversal-атак
-
Санитизация ввода — параметры рабочего каталога в бэкендах терминала проверяются по белому списку для предотвращения shell-инъекций
Подтверждение опасных команд
Перед выполнением любой команды Hermes проверяет её по составленному списку опасных шаблонов. При совпадении пользователь должен явно подтвердить выполнение.
Режимы подтверждения
Система подтверждения поддерживает три режима, настраиваемых через approvals.mode в ~/.hermes/config.yaml:
approvals:
mode: manual # manual | smart | off
timeout: 60 # секунд ожидания ответа пользователя (по умолчанию: 60)
| Режим | Поведение |
|---|---|
| manual (по умолчанию) | Всегда запрашивать подтверждение пользователя для опасных команд |
| smart | Использовать вспомогательную LLM для оценки риска. Команды с низким риском (например, python -c "print('hello')") автоодобряются. Действительно опасные команды автоотклоняются. Сомнительные случаи передаются на ручное подтверждение. |
| off | Отключает все проверки подтверждения — эквивалентно запуску с --yolo. Все команды выполняются без запросов. |
YOLO-режим
YOLO-режим отключает все запросы подтверждения опасных команд для текущей сессии. Его можно активировать тремя способами:
-
Флаг CLI: Запустить сессию с
hermes --yoloилиhermes chat --yolo -
Слэш-команда: Введите
/yoloво время сессии для переключения вкл/выкл -
Переменная окружения: Установите
HERMES_YOLO_MODE=1
Команда /yolo является переключателем — каждое использование включает или выключает режим:
> /yolo
⚡ YOLO mode ON — все команды автоодобряются. Используйте с осторожностью.
> /yolo
⚠ YOLO mode OFF — опасные команды будут требовать подтверждения.
YOLO-режим доступен как в CLI, так и в gateway-сессиях. Внутренне он устанавливает переменную окружения HERMES_YOLO_MODE, которая проверяется перед каждым выполнением команды.
Жёсткий блок-лист (всегда включён)
Некоторые команды настолько катастрофичны — необратимое удаление файловой системы, fork-бомбы, прямая запись на блочные устройства — что Hermes отказывается их выполнять независимо от:
-
Включенного
--yolo//yolo -
Установленного
approvals.mode: off -
Задач cron, работающих в безголовом режиме
approve -
Нажатия пользователем «разрешить всегда»
Блок-лист — это нижняя граница даже для --yolo. Он срабатывает до того, как команда попадает на уровень подтверждения, и не имеет флага переопределения. Ниже приведены текущие блокируемые шаблоны (не исчерпывающий список; синхронизирован с tools/approval.py::UNRECOVERABLE_BLOCKLIST):
| Шаблон | Почему это жёсткий блок |
|---|---|
rm -rf / и очевидные варианты |
Удаляет корень файловой системы |
rm -rf --no-preserve-root / |
Явный вариант «да, я имею в виду корень» |
:(){ :\|:& }; (bash fork bomb) |
Нагружает систему до перезагрузки |
mkfs.* на смонтированном корневом устройстве |
Форматирует живую систему |
dd if=/dev/zero of=/dev/sd* |
Обнуляет физический диск |
Перенаправление ненадёжных URL в sh на корневом уровне |
Слишком широкая поверхность для RCE-атак, чтобы разрешать |
Если вы наткнулись на блок-лист, вызов инструмента возвращает агенту поясняющую ошибку, и команда не выполняется. Если для легитимного рабочего процесса требуется одна из этих команд (например, вы управляете конвейером очистки и переустановки), запускайте её вне агента.
Тайм-аут подтверждения
Когда появляется запрос на подтверждение опасной команды, у пользователя есть настраиваемое время для ответа. Если ответ не получен в течение тайм-аута, команда отклоняется по умолчанию (fail-closed).
Настройте тайм-аут в ~/.hermes/config.yaml:
approvals:
timeout: 60 # секунд (по умолчанию: 60)
Что вызывает запрос подтверждения
Следующие шаблоны вызывают запросы на подтверждение (определены в tools/approval.py):
| Шаблон | Описание |
|---|---|
rm -r / rm --recursive |
Рекурсивное удаление |
rm ... / |
Удаление в корневом пути |
chmod 777/666 / o+w / a+w |
Права на запись для всех/остальных |
chmod --recursive с небезопасными правами |
Рекурсивная запись для всех/остальных (длинный флаг) |
chown -R root / chown --recursive root |
Рекурсивная смена владельца на root |
mkfs |
Форматирование файловой системы |
dd if= |
Копирование диска |
> /dev/sd |
Запись на блочное устройство |
DROP TABLE/DATABASE |
SQL DROP |
DELETE FROM (без WHERE) |
SQL DELETE без WHERE |
TRUNCATE TABLE |
SQL TRUNCATE |
> /etc/ |
Перезапись системного конфига |
systemctl stop/restart/disable/mask |
Остановка/перезапуск/отключение системных служб |
kill -9 -1 |
Убить все процессы |
pkill -9 |
Принудительное завершение процессов |
| Fork bomb-шаблоны | Fork-бомбы |
bash -c / sh -c / zsh -c / ksh -c |
Выполнение shell-команды через флаг -c (включая комбинированные флаги типа -lc) |
python -e / perl -e / ruby -e / node -c |
Выполнение скрипта через флаг -e/-c |
curl ... | sh / wget ... | sh |
Перенаправление удалённого содержимого в shell |
bash <(curl ...) / sh <(wget ...) |
Выполнение удалённого скрипта через подстановку процесса |
tee в /etc/, ~/.ssh/, ~/.hermes/.env |
Перезапись конфиденциального файла через tee |
> / >> в /etc/, ~/.ssh/, ~/.hermes/.env |
Перезапись конфиденциального файла через перенаправление |
xargs rm |
xargs с rm |
find -exec rm / find -delete |
Find с деструктивными действиями |
cp/mv/install в /etc/ |
Копирование/перемещение файла в системный конфиг |
sed -i / sed --in-place на /etc/ |
Редактирование системного конфига на месте |
pkill/killall hermes/gateway |
Предотвращение самоуничтожения |
gateway run с &/disown/nohup/setsid |
Предотвращает запуск gateway вне менеджера служб |
Процесс подтверждения (CLI)
В интерактивном CLI опасные команды показывают встроенный запрос на подтверждение:
⚠️ DANGEROUS COMMAND: recursive delete
rm -rf /tmp/old-project
[o]nce | [s]ession | [a]lways | [d]eny
Choice [o/s/a/D]:
Четыре варианта:
-
once — разрешить однократное выполнение
-
session — разрешить этот шаблон до конца сессии
-
always — добавить в постоянный белый список (сохраняется в
config.yaml) -
deny (по умолчанию) — заблокировать команду
Процесс подтверждения (Gateway/Мессенджеры)
На платформах обмена сообщениями агент отправляет информацию об опасной команде в чат и ожидает ответа пользователя:
-
Ответьте yes, y, approve, ok или go для подтверждения
-
Ответьте no, n, deny или cancel для отклонения
Переменная окружения HERMES_EXEC_ASK=1 автоматически устанавливается при запуске gateway.
Постоянный белый список
Команды, подтверждённые как «always», сохраняются в ~/.hermes/config.yaml:
# Постоянно разрешённые шаблоны опасных команд
command_allowlist:
- rm
- systemctl
Эти шаблоны загружаются при запуске и молча одобряются во всех будущих сессиях.
Авторизация пользователей (Gateway)
При запуске messaging gateway Hermes контролирует, кто может взаимодействовать с ботом, через многоуровневую систему авторизации.
Порядок проверки авторизации
Метод _is_user_authorized() проверяет в следующем порядке:
-
Флаг разрешения всех для платформы (например,
DISCORD_ALLOW_ALL_USERS=true) -
Список одобренных через DM-сопряжение (пользователи, одобренные через коды сопряжения)
-
Белые списки для конкретных платформ (например,
TELEGRAM_ALLOWED_USERS=12345,67890) -
Глобальный белый список (
GATEWAY_ALLOWED_USERS=12345,67890) -
Глобальное разрешение всех (
GATEWAY_ALLOW_ALL_USERS=true) -
По умолчанию: запрет
Белые списки платформ
Укажите разрешённые ID пользователей в виде значений, разделённых запятыми, в ~/.hermes/.env:
# Белые списки для конкретных платформ
TELEGRAM_ALLOWED_USERS=123456789,987654321
DISCORD_ALLOWED_USERS=111222333444555666
WHATSAPP_ALLOWED_USERS=15551234567
SLACK_ALLOWED_USERS=U01ABC123
# Кросс-платформенный белый список (проверяется для всех платформ)
GATEWAY_ALLOWED_USERS=123456789
# Разрешить всех на платформе (использовать с осторожностью)
DISCORD_ALLOW_ALL_USERS=true
# Глобальное разрешение всех (использовать с крайней осторожностью)
GATEWAY_ALLOW_ALL_USERS=true
No user allowlists configured. All unauthorized users will be denied.
Set GATEWAY_ALLOW_ALL_USERS=true in ~/.hermes/.env to allow open access,
or configure platform allowlists (e.g., TELEGRAM_ALLOWED_USERS=your_id).
Система DM-сопряжения
Для более гибкой авторизации Hermes включает систему сопряжения на основе кодов. Вместо того чтобы требовать ID пользователей заранее, неизвестные пользователи получают одноразовый код сопряжения, который владелец бота подтверждает через CLI.
Как это работает:
-
Неизвестный пользователь отправляет DM боту
-
Бот отвечает 8-символьным кодом сопряжения
-
Владелец бота запускает
hermes pairing approve <platform> <code>в CLI -
Пользователь получает постоянный доступ к этой платформе
Управляйте поведением обработки неавторизованных DM в ~/.hermes/config.yaml:
unauthorized_dm_behavior: pair
whatsapp:
unauthorized_dm_behavior: ignore
-
pair— значение по умолчанию. Неавторизованным DM отправляется ответ с кодом сопряжения. -
ignore— молча игнорирует неавторизованные DM. -
Секции платформ переопределяют глобальное значение по умолчанию, так что вы можете оставить сопряжение в Telegram, но держать WhatsApp молчащим.
Функции безопасности (на основе рекомендаций OWASP + NIST SP 800-63-4):
| Функция | Детали |
|---|---|
| Формат кода | 8 символов из 32-символьного однозначного алфавита (без 0/O/1/I) |
| Случайность | Криптографическая (secrets.choice()) |
| TTL кода | Истекает через 1 час |
| Ограничение частоты | 1 запрос на пользователя каждые 10 минут |
| Лимит ожидающих | Макс. 3 ожидающих кода на платформу |
| Блокировка | 5 неудачных попыток → блокировка на 1 час |
| Безопасность файлов | chmod 0600 на всех файлах данных сопряжения |
| Логирование | Коды никогда не логируются в stdout |
Команды CLI для сопряжения:
# Список ожидающих и одобренных пользователей
hermes pairing list
# Подтвердить код сопряжения
hermes pairing approve telegram ABC12DEF
# Отозвать доступ пользователя
hermes pairing revoke telegram 123456789
# Очистить все ожидающие коды
hermes pairing clear-pending
Хранение: Данные сопряжения хранятся в ~/.hermes/pairing/ в JSON-файлах по платформам:
-
{platform}-pending.json— ожидающие запросы на сопряжение -
{platform}-approved.json— одобренные пользователи -
_rate_limits.json— отслеживание ограничений частоты и блокировок
Изоляция контейнеров
При использовании бэкенда терминала docker Hermes применяет строгие меры безопасности к каждому контейнеру.
Флаги безопасности Docker
Каждый контейнер запускается с этими флагами (определены в tools/environments/docker.py):
_SECURITY_ARGS = [
"--cap-drop", "ALL", # Сбросить ВСЕ Linux-способности
"--cap-add", "DAC_OVERRIDE", # Root может писать в смонтированные каталоги
"--cap-add", "CHOWN", # Менеджерам пакетов нужно владение файлами
"--cap-add", "FOWNER", # Менеджерам пакетов нужно владение файлами
"--security-opt", "no-new-privileges", # Блокировать повышение привилегий
"--pids-limit", "256", # Лимит количества процессов
"--tmpfs", "/tmp:rw,nosuid,size=512m", # /tmp с ограничением по размеру
"--tmpfs", "/var/tmp:rw,noexec,nosuid,size=256m", # Без exec в /var/tmp
"--tmpfs", "/run:rw,noexec,nosuid,size=64m", # Без exec в /run
]
Лимиты ресурсов
Ресурсы контейнера настраиваются в ~/.hermes/config.yaml:
terminal:
backend: docker
docker_image: "nikolaik/python-nodejs:python3.11-nodejs20"
docker_forward_env: [] # Только явный белый список; пустой массив не пропускает секреты в контейнер
container_cpu: 1 # Ядра CPU
container_memory: 5120 # МБ (по умолчанию 5 ГБ)
container_disk: 51200 # МБ (по умолчанию 50 ГБ, требуется overlay2 на XFS)
container_persistent: true # Сохранять файловую систему между сессиями
Постоянство файловой системы
-
Постоянный режим (
container_persistent: true): Монтирует/workspaceи/rootиз~/.hermes/sandboxes/docker/<task_id>/ -
Эфемерный режим (
container_persistent: false): Использует tmpfs для рабочей области — всё теряется при очистке
Сравнение безопасности бэкендов терминала
| Бэкенд | Изоляция | Проверка опасных команд | Лучше всего для |
|---|---|---|---|
| local | Нет — выполняется на хосте | ✅ Да | Разработка, доверенные пользователи |
| ssh | Удалённая машина | ✅ Да | Запуск на отдельном сервере |
| docker | Контейнер | ❌ Пропущено (контейнер — граница) | Продакшн gateway |
| singularity | Контейнер | ❌ Пропущено | HPC-среды |
| modal | Облачная песочница | ❌ Пропущено | Масштабируемая облачная изоляция |
| daytona | Облачная песочница | ❌ Пропущено | Постоянные облачные рабочие области |
| vercel_sandbox | Облачная microVM | ❌ Пропущено | Облачное выполнение с сохранением состояния снимков |
Проброс переменных окружения {#environment-variable-passthrough}
Как execute_code, так и terminal удаляют конфиденциальные переменные окружения из дочерних процессов, чтобы предотвратить извлечение учётных данных LLM-сгенерированным кодом. Однако навыки, объявляющие required_environment_variables, легитимно нуждаются в доступе к этим переменным.
Как это работает
Два механизма позволяют пропускать определённые переменные через фильтры песочницы:
1. Проброс уровня навыка (автоматический)
Когда навык загружается (через skill_view или команду /skill) и объявляет required_environment_variables, любые из этих переменных, которые действительно установлены в окружении, автоматически регистрируются для проброса. Отсутствующие переменные (в состоянии «требуется настройка») не регистрируются.
# В frontmatter SKILL.md навыка
required_environment_variables:
- name: TENOR_API_KEY
prompt: Tenor API key
help: Get a key from https://developers.google.com/tenor
После загрузки этого навыка TENOR_API_KEY передаётся в execute_code, terminal (local), и удалённые бэкенды (Docker, Modal) — без необходимости ручной настройки.