ИИ-агенты и автоматизация

Безопасность движка инференса: атака через вывод

Безопасность движка инференса: атака через вывод

За август мы разобрали три способа, которыми модель делает не то, что от неё ждут: инъекцию в документе, побег агента из песочницы, самораспространяющиеся идеи между агентами. Появился четвёртый, и он устроен принципиально иначе. Все предыдущие работали на уровне смысла: модель прочитала текст и восприняла его как указание. Этот работает уровнем ниже — вывод модели попадает в разбор на стороне движка инференса, и если в разборщике есть уязвимость, специально составленный вывод может привести к выполнению произвольного кода прямо на сервере. Разбираем механику, отдельный сюжет про извлечение весов через обычные ответы, и что из этого следует для тех, кто запускает модели у себя.

Чем это отличается от всего предыдущего

Разграничение важно, потому что защиты у этих угроз разные.

Промпт-инъекция. Во входных данных спрятана инструкция, модель принимает её за задачу. Уровень — смысл текста. Защита — ограничение прав того, что модель может сделать после прочтения. Мы разбирали случай, когда инъекцию спрятали в судебном документе.

Побег из песочницы. Агент выполняет сгенерированный код, и обычный контейнер этому не преграда, потому что делит ядро с хостом. Уровень — операционная система. Защита — микровиртуальные машины, подробности отдельно.

Самораспространяющиеся идеи. Текст в общей памяти агентов воспроизводит сам себя. Уровень — архитектура многоагентной системы. Защита — строка в системном промпте и ограничение общей памяти.

Атака на движок. Вывод модели разбирается программой, и в разборщике есть ошибка. Уровень — код инфраструктуры. Защита — обновления и изоляция самого движка.

Общее у первых трёх: они про то, что модель решила сделать. Четвёртый про то, что программа не смогла корректно обработать. Это обычная уязвимость в разборе данных — того же класса, что переполнение буфера при чтении картинки. Новизна только в источнике данных: их производит модель.

Как это выглядит на практике

Механика описывается коротко.

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

Разборщик, как любой разборщик, может содержать ошибку. Если специально составленный вывод модели попадает в такую ошибку, последствия — обычные для уязвимостей разбора: от падения процесса до выполнения кода.

Задокументированный пример относится к разбору вызовов инструментов в одном из популярных движков и имеет присвоенный номер уязвимости. То есть это не гипотеза, а описанный случай с исправлением.

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

Почему движок вообще что-то разбирает

Стоит объяснить, откуда берётся сама возможность, потому что интуитивно кажется, что модель просто возвращает текст.

Она и возвращает текст — но текст в оговорённом формате. Когда модель вызывает инструмент, она не «вызывает» его в буквальном смысле: она генерирует последовательность, которая по договорённости означает вызов. Кто-то должен эту последовательность распознать и превратить в структуру.

Раньше этим занимался клиент. Сейчас всё больше работы переехало в движок: он сам распознаёт вызовы инструментов, сам собирает потоковый вывод в структуры, сам обрабатывает специальные признаки. Клиенту отдаётся уже готовый объект.

Удобно — и именно поэтому появилась поверхность атаки. Разбор происходит на сервере, до того как что-либо дойдёт до вашего кода, и с правами процесса инференса.

Полезная аналогия: это тот же переход, что случился когда-то с обработкой изображений. Пока картинку просто хранили, ничего не происходило. Как только её начали разбирать для показа, появился целый класс уязвимостей в декодерах. Здесь то же самое, только вместо картинки — вывод модели.

Что это значит для выбора между своим и чужим

Наблюдение, которое стоит вынести отдельно, потому что оно меняет одну сторону расчёта.

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

Эта история добавляет третью составляющую — эксплуатационную ответственность. Разворачивая модель у себя, вы берёте на себя не только железо, но и сопровождение движка: следить за версиями, читать бюллетени, применять исправления, изолировать процесс.

Для команды с отлаженной практикой обновлений это привычная работа. Для команды, которая развернула модель один раз и забыла, — накапливающийся риск, о котором в расчёте окупаемости обычно не пишут.

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

Отдельный сюжет: веса, спрятанные в ответах

Вторая линия исследований, которая заслуживает упоминания, потому что она про доверие к провайдеру.

Сторона, контролирующая сервер инференса, может незаметно вкраплять информацию в обычные ответы модели — так, что для читателя они выглядят нормально. Достаточным объёмом ответов таким способом можно вынести наружу сами веса модели.

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

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

Что делать, если вы разворачиваете модели сами

Практическая часть, и она короче, чем кажется.

  1. Обновляйте движок инференса как обычное ПО. Это очевидно и делается редко: движок воспринимают как часть модели, а не как сервис с уязвимостями. У него есть версии, есть исправления и есть номера уязвимостей.
  2. Изолируйте процесс инференса. Он не должен иметь доступа ни к чему, кроме того, что нужно для работы: ни к секретам, ни к внутренней сети, ни к соседним сервисам.
  3. Не считайте вывод модели доверенными данными. Он проходит разбор в нескольких местах — в движке, в вашем коде, в клиенте. Каждое из них надо считать точкой, куда попадают недоверенные данные.
  4. Проверяйте происхождение весов. Файлы весов — это не только числа; вокруг них бывают конфигурации и шаблоны, которые исполняются. Скачанное из непроверенного места стоит проверять как любую зависимость.

Отдельно про наш контур: при работе через API движок инференса — не ваша забота. Мы передаём запросы к моделям, содержимое не разбираем и не храним; перечень того, что остаётся, — в llms.txt. Это не делает вас неуязвимыми — инъекции и права агента остаются вашей ответственностью, — но снимает целый слой инфраструктурных вопросов.

Чего мы не утверждаем

Мы не воспроизводили атаки. Всё описанное — из публикаций, перечисленных в источниках.

Не называем конкретные версии уязвимыми. Уязвимости исправляются, и актуальное состояние нужно смотреть в бюллетенях сопровождающих, а не в статье.

Не утверждаем, что это массовое явление. Речь про описанный класс, а не про наблюдаемую волну инцидентов.

Не даём инструкций по эксплуатации. Разбираем механику на уровне, достаточном для защиты, и не приводим ни рабочих последовательностей, ни деталей конкретных ошибок.

Не оцениваем конкретные движки. Уязвимости находят во всех сложных программах; наличие исправленной ошибки говорит о том, что за проектом следят, а не о том, что он плох.

Что держать в голове

Появился четвёртый способ, которым модель создаёт проблемы, и он не про смысл текста, а про код инфраструктуры: вывод модели попадает в разборщик, а в разборщике бывают ошибки.

Практический вывод для тех, кто разворачивает у себя: движок инференса — это сервис, а не часть модели. Его надо обновлять, изолировать и относиться к его входу как к недоверенным данным, потому что этот вход производит модель.

Как мы отделяем проверенное от предполагаемого — на странице о проекте. Отдельный ключ с собственным лимитом под каждый сценарий: keydealer.ru/login.

Частые вопросы

В чём суть угрозы?

Вывод модели попадает в разбор на стороне движка инференса. Если в разборщике есть уязвимость, специально составленный вывод может привести к выполнению произвольного кода на сервере.

Это то же самое, что промпт-инъекция?

Нет. Инъекция заставляет модель сделать что-то не то. Здесь вывод модели атакует программу, которая её запускает, — уровнем ниже.

Кого это касается?

В первую очередь тех, кто разворачивает модели у себя. При работе через API движок инференса — забота провайдера.

Что такое извлечение весов через ответы?

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

Что с этим делать?

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

Источники