Назад к блогу

Безопасность AI-ассистентов: как один отладочный флаг и запрос к файловой системе обнажают границы доверия

Безопасность AI-ассистентов: как один отладочный флаг и запрос к файловой системе обнажают границы доверия

Два инцидента с ассистентом Meta Muse показывают, что граница доверия проходит не вокруг агента, а внутри него: недокументированный конфигурационный ключ позволил перенаправить аудиопоток диктовки на чужой сервер, а обычная просьба заархивировать файлы обернулась утечкой корневой файловой системы с SSH-ключами и внутренней документацией. Разбор интересен тем, что оба случая обходятся без взлома периметра — эксплуатируется сама логика доверенного подписанного приложения, а реакция вендора и сообщества на эти находки разошлась радикально.

Разбираем два инцидента вокруг Meta Muse. В первом недокументированный ключ конфигурации позволил непривилегированному процессу перенаправить трафик диктовки на чужой сервер. Во втором ассистент по обычной просьбе собрал и отправил наружу архив со своей корневой файловой системой. Вопрос нетривиален потому, что оба случая — не про взлом периметра, а про то, где именно проходит граница доверия внутри уже доверенного агента.

Что произошло

На macOS локальные процессы и произвольные скрипты в непривилегированном пользовательском контексте могли перезаписать значение настройки, задающей облачный сервер для приёма аудио диктовки и возврата транскрипций, — без прав администратора и без запросов авторизации ОС. Перезаписав настройку, атакующий тихо перенаправлял исходящий трафик диктовки на подконтрольный сервер.

Во втором инциденте автор запросил у Muse заархивировать доступные ему файлы и отправить их в Google Drive — и агент это выполнил. Загрузка составила около 2.7 ГБ в сжатом виде и 6.8 ГБ в распакованном. Архив содержал корневую файловую систему Linux-окружения сессии, системные файлы Ubuntu, внутреннюю документацию Muse, код интеграций, шаблоны приложений, файлы памяти, логи агента и SSH-ключи.

Наиболее интересные файлы лежали в /home/hatch, /opt/hatch и /opt/hatch-image, где Hatch — внутреннее имя Meta для Muse. В домашней директории агента находились SOUL.md, IDENTITY.md, USER.md, MEMORY.md, AGENTS.md и TOOLS.md, а также каталоги документации, памяти, рабочих проектов, каналов, хуков и подписок. Каталог agents/ содержал 113 записей субагентов с JSONL-трассировками. Под /opt/hatch/skills/ было около 68 каталогов навыков, обычно в паре SKILL.md с инструментом командной строки или вспомогательным кодом. /opt/hatch/runtime-cell/ содержал 18 файлов, включая скрипты сборки корневой файловой системы, запуска через systemd-nspawn и стартовых хуков и демонов.

Автор сообщил о находках через программу bug bounty Meta и не публиковал архив, ключи или логи сессии. Он не установил, были ли SSH-ключи активны и какой доступ они могли дать.

Как это квалифицировали

Meta рассматривала дефект как внутреннюю ошибку конфигурации, а не как повод для формального присвоения CVE. Представитель Meta Superintelligence Labs Дэвид Синглтон описал проблему как локальную конфигурационную, требующую предварительного выполнения кода, а команда устранила её, молча удалив внутренний ключ отладочной настройки из production-сборок.

Сообщество эту трактовку отвергло. Специалисты по безопасности указали, что первоначальный доступ тривиализуется социальной инженерией вроде ClickFix, тогда как обход Apple Transparency, Consent, and Control традиционно сложен. В инженерных дискуссиях на Hacker News и Reddit отмечалось, что, упаковав кросс-синхронизацию устройств, полные права на диск, аудиопотоки и истории приватных чатов в не-песочный подписанный агент с изменяемой отладочной конечной точкой, Meta фактически дала обычному вредоносному ПО беспрепятственный канал обхода платформенных защит без срабатывания операционных оповещений. Уордл отметил, что эксплойт позволяет манипулировать агентом вместо разработки сложного отдельного инфостилера, превращая подписанного доверенного ассистента в поверхность атаки.

Механика: флаг диктовки

Локальный процесс или скрипт перезаписывает endo_voyager_dictation_endpoint — прав администратора и запросов авторизации ОС для этого не требуется. Когда пользователь активирует диктовку, настольный клиент отправляет на настроенный endpoint сырое аудио микрофона вместе с действующим токеном аутентификации учётной записи Muse. Атакующий может держать прокси-сервер, который захватывает токены и аудио, одновременно пересылая легитимный трафик обратно на серверы Meta, чтобы не вызвать подозрений.

С действующими сессионными учётными данными и контролем над конвейером команд атакующий может проводить prompt injection, добавляя скрытые инструкции к голосовым запросам. Это заставляет ассистента выполнять несанкционированные фоновые задачи, например выгружать локальные документы или историю сообщений WhatsApp.

После публичного раскрытия Meta выпустила hotfix для macOS-приложения Muse: внутренняя отладочная настройка была удалена из production-сборок, что предотвратило локальное изменение назначения сервера диктовки.

Механика: экспорт файловой системы

Отдельный случай — не про флаг, а про обычный запрос. Автор попросил Muse заархивировать видимые файлы и отправить их в Google Drive, и агент это выполнил.

В домашней директории агента находились SOUL.md, IDENTITY.md, USER.md, MEMORY.md, AGENTS.md и TOOLS.md. Из них назначение в рантайме описано только для MEMORY.md — это краткий лист фактов, предпочтений и обязательств.

Помимо файлов агента, экспорт содержал builders для документов, PDF, презентаций, таблиц и Markdown, а также отдельный навык magic-moment с кодом для составления карточек и видео, скриптами захвата браузера, шрифтами и брендовыми ресурсами. В образе был установлен Codex CLI по пути /opt/hatch-image/bin/codex версии 0.149.0, но свидетельств его использования как кодирующего агента не найдено.

Hatch использует входящий в комплект bubblewrap — инструмент песочницы Linux; бинарник лежит в codex-resources/bwrap и идентифицирует себя как bubblewrap built for Codex. Muse применяет его для изоляции ffmpeg и ffprobe при обработке видео, создании миниатюр и проверке файлов. Эти задачи выполняются без сетевого доступа и дополнительных привилегий, от пользователя nobody, с доступом к каталогам /input и /output. Если bubblewrap отсутствует, они завершаются ошибкой failed to prepare ffmpeg sandbox.

Ночной процесс dream

Ночной «dream» просматривает недавние разговоры и записывает guidance (руководящие указания) для будущих сессий. В конкретном случае он выявил, что пользователь предпочитает короткие ответы, не любит повторные уточнения и не запрашивал непрошеные счёты NFL. Датированные записи dream лежат в ~/dreams/, а отдельный файл ALIGNMENT_SYNTHESIS.md превращает эти наблюдения в постоянное руководство. Сам текст dream-файлов в промпт не внедрялся.

В экспорт попали файлы памяти и dream-записи: в корне экспортированной файловой системы были каталоги ~/memory/, memory/bank/ и ~/dreams/, а также ~/MEMORY.md.

Где нарушаются границы доверия

Перезапись endo_voyager_dictation_endpoint нарушает границу между агентом и локальными процессами: непривилегированный код меняет конфигурацию, которой пользуется доверенный клиент. Отправка аудио вместе с токеном аутентификации нарушает границу между пользователем и рантаймом сессии — перехват одного и того же трафика сразу раскрывает и содержимое ввода, и учётные данные. Возможность prompt injection через тот же канал нарушает границу между данными и командами: скрытые инструкции в голосовом запросе превращаются в фоновые задачи агента.

Конфиденциальность входных данных и учётные данные оказываются скомпрометированы одновременно именно потому, что клиент шлёт их одним потоком на один endpoint. Это соответствует риску LLM10 Unbounded Consumption из OWASP LLM Top 10: злоумышленник получает прямой контроль над командным конвейером агента и может инициировать неограниченное выполнение задач. Смежный риск — Memory и RAG poisoning: вредная инструкция может попасть в долговременную память, summary, embedding store или общий контекст, после чего агент будет использовать загрязнённые данные в будущих сессиях.

Условия эксплуатации и что видит пользователь

В разборе похожего случая перечислены четыре условия эксплуатации, и все они «не имеют ни одной защиты». Конкретное значение флага задаётся конфигурацией soulEvil.chance: 1: soulEvil при таком значении агент всегда в «злом» режиме, при этом пользователь не видит разницы — тот же интерфейс, тот же чат. Права процесса и доступность файловой системы не описаны. Отсутствие санитизации подтверждается тем, что на пути сообщения нет ни одной проверки содержимого, а единственная «санитизация» находится в 867 строках brain core. Предложенные защитные механизмы Content Boundary Enforcement и Memory Sanitization не реализованы.

В момент выгрузки пользователь не видит разницы: тот же интерфейс, тот же чат. Решение о подмене логируется только на уровне debug, который в проде выключен. Отдельно действует принцип «Model-visible means logged» — то, что видно модели, попадает в логи. Архитектура предоставляет точки расширения до и после выполнения, которые плагин может использовать для логирования, проверки аргументов, отклонения небезопасных запросов, применения политики компании, измерения времени выполнения, редактирования чувствительного вывода, добавления верификации и преобразования результатов. При этом sandbox и approval — независимые механизмы контроля.

Повторное использование сессии

Повторно использованный идентификатор сессии может сохранить как состояние разговора, так и принадлежащий сессии shell-процесс. Состояние разговора выводится из журнала сессии: всё, что попадает в запрос к модели, должно быть восстановимо из потока событий сессии, что поддерживает возобновление, форк, повтор и сохранение. События сессии — это долговечные факты, записываемые в журнал сессии, включая сообщения пользователя, сообщения ассистента, вызовы инструментов, результаты инструментов, изменения разрешений и границы ходов; их следует использовать, когда информация должна пережить перезагрузку или повтор.

Риск создаёт конфигурация danger-full-access: в отличие от пресета workspace-write, который ограничивает запись рабочим пространством и требует подтверждения (approval: ask), этот режим не запрашивает подтверждений (approval: never) и может изменять любой путь, доступный процессу среды выполнения, поэтому его следует использовать только внутри одноразовой копии репозитория или контейнера.

Компромиссы и почему сделано именно так

Meta не выпустила формального security advisory и не координировала действия с CVE Numbering Authority, поэтому уязвимость осталась без официального CVE-обозначения. Вместо раскрытия через CVE команда инженеров тихо удалила ключ отладочной настройки из production-сборок. Организационный компромисс здесь — приоритет скорости и минимизации публичного раскрытия над формальной процедурой: после публичного раскрытия Meta выпустила hotfix для macOS-приложения Muse, и исправление свелось к удалению внутренней отладочной настройки из production-сборок.

Архитектурно снизить риск могли бы pre-execute и post-execute точки расширения — они позволяют валидировать аргументы инструментов, добавлять логирование, отклонять небезопасные запросы, применять политику компании, измерять время выполнения, редактировать чувствительный вывод, добавлять проверку и преобразовывать результаты; это названо более масштабируемым подходом, чем встраивание всей политики в каждый отдельный инструмент. Sandbox и approval смоделированы как два независимых контроля, и есть пресеты разрешений: workspace-write с sandbox: workspace-write и approval: ask, а danger-full-access с sandbox: danger-full-access и approval: never. Однако в разборе exec-approval-manager показано, что если пользователь не ответил на запрос одобрения, команда выполняется, и что любой WebSocket-клиент может одобрить запрос любого другого клиента без проверки identity.

Как сравнивали и что получилось

Отдельного бенчмарка нет. Есть два количественных результата, оба — из описания инцидентов, а не из контролируемого замера.

Первый — объём выгрузки: около 2.7 ГБ в сжатом виде и 6.8 ГБ в распакованном. Условия: автор запросил у Muse заархивировать доступные ему файлы и отправить их в Google Drive; агент выполнил запрос. Что именно попало в архив, перечислено выше; что осталось за пределами видимости агента — не указано.

Второй — состав рантайма: 113 записей субагентов с JSONL-трассировками в каталоге agents/, около 68 каталогов навыков под /opt/hatch/skills/, 18 файлов в /opt/hatch/runtime-cell/, версия Codex CLI 0.149.0 по пути /opt/hatch-image/bin/codex.

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

Что из этого следует на практике

Доверенный подписанный агент с широкими разрешениями и изменяемой конфигурацией сам становится поверхностью атаки. Отсюда несколько следствий.

Конфигурацию, влияющую на маршрутизацию трафика и учётные данные, нельзя оставлять изменяемой из непривилегированного контекста. Если значение ключа можно перезаписать без прав администратора и без запроса авторизации ОС, оно перестаёт быть настройкой и становится точкой входа.

Аудио и токен аутентификации, уходящие одним потоком на один endpoint, компрометируются вместе. Разделение этих данных по разным каналам или разным получателям уменьшает цену перехвата одного соединения.

Пользователь не видит разницы между нормальным и подменённым поведением, а решение о подмене логируется на уровне debug, выключенном в проде. Наблюдаемость должна отвечать на вопросы расследования: какой входной запрос запустил цепочку, какие документы были извлечены, какие tools вызваны, какие параметры переданы, кто подтвердил действие и какой результат получился. Минимальный набор — request ID, идентификатор агента и идентификатор пользователя-человека отдельно, логи вызванных tools, трейсы для многоагентных процессов, записи подтверждений человеком и неизменяемый журнал безопасности для чувствительных операций. Полезны две метрики: время обнаружения (сколько проходит от аномалии до осведомлённости человека) и покрытие расследований (доля алертов, которые действительно расследуются).

События разделяются на домены. Session events — долговечные факты, записываемые в журнал сессии: сообщения пользователя и ассистента, вызовы инструментов и их результаты, изменения разрешений, границы ходов. Agent events описывают живое выполнение: pre-step processing, запросы агента, валидация, продолжение, остановка. Capability events привязывают поведение к подсистеме без необходимости импортировать её напрямую: файловая система, инструменты, телеметрия. Журнал сессии служит источником контекста для модели, а не только файлом аудита.

Меры защиты, применимые к другим ассистентам с доступом к инструментам и данным:

  • Инструменты ограничиваются allowlist под конкретную функцию, а не полным набором доступных инструментов.
  • Параметры tool call валидируются до выполнения и на стороне самого инструмента.
  • Права разделяются: read-only по умолчанию, а write/delete/outbound actions — через отдельное разрешение.
  • Runtime изолируется через sandbox, контейнер, microVM, ограниченный filesystem и egress.
  • Промпты, allowlist инструментов, политики и настройки агентов живут в версионированной системе, типа гита, с подписью конфигураций и проверкой перед деплоем.
  • Для опасных действий нужен human-in-the-loop: человеку показывают понятное описание действия, а подтверждение попадает в журнал безопасности.
  • Откат конфигураций входит в чеклист восстановления вместе с версионированием и подписью артефактов.

Для памяти агента минимальные правила: изоляция между пользователями и клиентскими контурами, указание источника для каждого элемента, TTL для временного контекста, проверки целостности при извлечении, карантин и откат для отравленной памяти.

Главная идея Zero Trust для таких систем: агенту нельзя доверять по умолчанию только потому, что он запущен внутри компании или работает от имени легитимного пользователя. Его идентификация, права, вызовы инструментов, память и действия проверяются так, будто компрометация рано или поздно случится.

Источники

Похожее