TL;DR
ToFu — фреймворк, который берёт описание инструмента, которое агент и так читает (например, «путь к файлу внутри рабочей папки»), и превращает его в автоматическую проверку. Для каждого аргумента он подбирает типичные «злые» значения (../../etc/passwd, внутренние адреса, опасные команды). Затем прогоняет инструмент и смотрит, нарушил ли тот собственное обещание, даже если ошибки не было. Модель при этом не судья: она лишь помогает сопоставить описание с набором проверок.
Главная находка: инструмент, подключённый к агенту, почти никогда не проверяет то, что обещает в описании. Из 273 открытых MCP-серверов баги нашлись в 118. Инструмент «читает файлы в рабочей папке», но спокойно отдаёт файл из любого места. Падения нет, ошибки нет, обычные проверки молчат. Вторая находка — атака Repeat-After-Me. Вы просите модель «повторить дословно» текст, который выглядит как вызов инструмента, и система запускает этот вызов с вашими аргументами. Модель просто повторила текст, но оркестратор (слой, который превращает ответ модели в запуск инструмента) принял его за команду.
Вывод для практика: аргументы, которые сгенерировала модель, нельзя считать безопасными. Защита «на уровне промпта» не заменяет проверки на стороне инструмента. Сам ToFu требует кода (Python, фаззер), поэтому читателю он нужен как логика проверки и как повод осторожнее выбирать MCP-серверы.
Схема метода
ШАГ 1: Прочитать метаданные инструмента (описание + схема аргументов)
→ нормализованный список аргументов с их смыслом
ШАГ 2: Для каждого аргумента подобрать «санитайзеры» из корпуса (74 шт., по классам CWE)
→ путь → проверки выхода из папки; URL → проверки схемы и адреса; команда → проверки оболочки
(LLM помогает сопоставить описание и проверки, вердикт не выносит)
ШАГ 3: Сгенерировать стартовые значения и «обвязку» фаззера
→ значения валидны по схеме, поэтому проходят обычный путь агента
ШАГ 4: Запустить инструмент с мутациями этих значений
ШАГ 5: Поймать нарушение одним из двух способов:
• инструмент виден изнутри → трассировщики записывают реальные обращения к файлам, процессам, сети
• инструмент «чёрный ящик» → пометить злой вход и проверить, принял ли его инструмент
→ отчёт: какой вызов, какой аргумент, какое свойство нарушено
Шаги 1–5 выполняются кодом (Python, фаззер Atheris). В одном чате это не воспроизвести.
Пример применения
Оригинальный метод требует кода. Но его логику можно применить до подключения чужого MCP-сервера: попросить LLM составить план проверки по описаниям инструментов. Затем человек или разработчик проверяет по этому плану. Модель плана не выносит вердикта «безопасно», как и в самой статье.
Задача: Аналитик маркетплейса хочет подключить к Claude Code стороннего MCP-сервера «работа с файлами и загрузка страниц». В рабочей папке лежат выгрузки продаж и договоры с поставщиками. Он не разработчик, но хочет понять, что именно проверить, прежде чем давать агенту доступ.
Промпт:
Ты помогаешь составить план проверки безопасности инструментов MCP-сервера.
Работай по схеме: для каждого аргумента выведи, что он означает по описанию,
какое свойство безопасности из этого следует и как его нарушить.
Инструменты сервера:
1. read_file(path: string) — "Читает файл внутри рабочей папки ~/work/sales"
2. fetch_page(url: string) — "Загружает страницу по публичному адресу и возвращает текст"
3. save_report(filename: string, content: string) — "Сохраняет отчёт в папку reports"
Для КАЖДОГО аргумента составь таблицу:
- Аргумент
- Что он означает по описанию
- Какое свойство безопасности подразумевает описание
- 5 «злых» значений, которые ещё проходят по типу string
- Что наблюдать, чтобы доказать нарушение (какие файлы открылись, какой адрес запрошен)
Не выноси вердикт «безопасно/небезопасно»: только план проверки.
В конце — 3 вопроса автору сервера, на которые нет ответа в описаниях.
Результат: Модель выдаст три таблицы по одной на аргумент (path, url, filename). Для пути будет проверка выхода за папку, для адреса — ограничения по схеме и назначению (внутренние адреса), для имени файла — запись за пределы reports. Для каждого аргумента будет список злых значений и описание того, что наблюдать. В конце появятся уточняющие вопросы автору сервера. Дальше человек прогоняет эти значения на тестовой копии папки, а не на рабочей.
Почему это работает
Слабость. Тип аргумента — просто «строка». Из него нельзя понять, что проверять: путь, адрес и команда требуют разных защит. Обычный фаззинг ищет падения, а здесь инструмент отрабатывает «успешно» и отдаёт то, что не должен. Падения нет, значит, ничего не видно.
Сильная сторона. Смысл аргумента уже записан в описании, которое инструмент отдаёт модели. «Файл внутри рабочей папки» — это готовое требование: путь не должен выходить за корень. Модель хорошо переводит такие фразы в набор проверок и подбирает подходящие злые значения.
Как метод это использует. Он разворачивает привычный порядок: не «ищем известную уязвимость и смотрим, у кого она есть», а «берём каждый аргумент, выводим из описания обещание и пытаемся его нарушить». Проверку выносит не LLM, а наблюдение за реальным поведением: открытые файлы, запрошенный адрес.
Рычаги:
- Описание аргумента → чем точнее написано («только *.csv в ~/work/sales»), тем острее проверка. Расплывчатое описание даёт расплывчатый план.
- Число злых значений (в шаблоне 5) → больше для критичных инструментов, меньше для быстрой оценки.
- Запрет на вердикт → уберите, если хотите предварительную оценку рисков. Помните, что это догадка модели, а не проверка.
- Класс аргумента → добавьте свои (идентификатор клиента, SQL-запрос, имя хоста), если в инструментах есть такие.
Шаблон промпта
Это моя адаптация логики ToFu под чат. В статье LLM только сопоставляет описание и проверки и подбирает стартовые значения, вердикт выносят трассировщики и оракулы в коде.
Ты помогаешь составить план проверки безопасности инструментов, которые вызывает LLM-агент.
Принцип: аргументы, сгенерированные моделью, считаются недоверенными. Описание инструмента
задаёт обещание, и его нужно попытаться нарушить.
<Инструменты>
{список_инструментов_с_описаниями_и_аргументами}
Инструменты>
<Контекст>
Рабочая среда: {папка_сеть_права_доступа}
Что есть ценного рядом: {чувствительные_данные}
Контекст>
<Логика>
Для КАЖДОГО аргумента каждого инструмента:
1. Определи смысл аргумента по описанию (путь / URL / команда / запрос / идентификатор / другое).
2. Выведи подразумеваемое свойство безопасности (например: «путь остаётся внутри корня»).
3. Назови {число_значений} «злых» значений, которые проходят по схеме, но нарушают свойство.
4. Укажи наблюдение, которое докажет нарушение (какой файл открыт, какой адрес запрошен,
какая команда запущена), а не «ждать ошибки».
5. Если описание расплывчато и свойство вывести нельзя — пометь «неясно» и сформулируй
вопрос автору инструмента.
Логика>
<Правила>
- Не выноси вердикт «безопасно». Только план проверки.
- Не считай отсутствие ошибки признаком безопасности.
- Тесты предназначены для тестовой копии данных, не для рабочей.
Правила>
<Формат>
Таблица на каждый инструмент: Аргумент | Смысл | Свойство | Злые значения | Что наблюдать.
В конце — список вопросов автору и три самых рискованных аргумента.
Формат>
Что подставлять: {список_инструментов_с_описаниями_и_аргументами} — названия, описания и аргументы инструментов (из конфига MCP-сервера или его README). {папка_сеть_права_доступа} — где работает агент и что ему доступно. {чувствительные_данные} — что лежит рядом (договоры, ключи, выгрузки). {число_значений} — обычно 5.
🚀 Быстрый старт — вставь в чат:
Вот шаблон плана проверки инструментов агента. Адаптируй под мою задачу: хочу подключить
MCP-сервер {название_или_описание_сервера}. Задавай вопросы, чтобы заполнить поля.
[вставить шаблон выше]
LLM спросит, какие инструменты есть у сервера, что написано в их описаниях и что лежит рядом с агентом. Это нужно потому, что весь метод строится на описаниях аргументов. Без них модель не выведет, что именно проверять. Она возьмёт структуру из шаблона и заполнит под ваш сервер.
Ограничения
⚠️ Метод требует кода: настоящий ToFu — это Python-фаззер с трассировщиками (21 трассировщик, 74 проверки). Читатель его не запустит. Чатовая версия только готовит план, а проверять придётся вручную или с разработчиком.
⚠️ Модель не вердикт-машина: в статье LLM намеренно не используется как судья безопасности. Если просить «оцени, безопасен ли сервер», получите догадку, а не проверку.
⚠️ Расплывчатое описание ломает метод: проверки выводятся из описаний. Если описание пустое или двусмысленное, ToFu не может вывести обещание, а значит, не может его проверить.
⚠️ Промпт от этого не защищает: уязвимость сидит в инструменте и оркестраторе, а не в модели. Инструкция агенту «не выходи за папку» не заменяет проверку пути в самом инструменте.
⚠️ Нет сравнения моделей и защит: авторы не проверяли, какие системные инструкции или настройки агента снижают риск. Практические меры для пользователя читателю придётся достраивать самому.
⚠️ Охват: проверялись открытые MCP-серверы, главным образом на Python (интроспекция идёт через хуки Python). Закрытые и написанные на других языках проверяются только как «чёрный ящик», слабее.
Как исследовали
Идея была простой: описание инструмента, которое помогает модели его вызывать, помогает и тестировать этот инструмент. Авторы собрали корпус из 74 «санитайзеров» (готовых проверок по классам уязвимостей CWE) и написали систему, которая сама сопоставляет их с аргументами инструмента. Дальше она запускает фаззер Atheris и следит за реальными обращениями к файлам, процессам и сети. Для закрытых инструментов используется запасной режим: помечается злой вход и проверяется, принял ли его инструмент.
Проверяли на 273 открытых MCP-серверах с 3405 инструментами. Нашли подтверждённые баги в 343 инструментах из 118 серверов: выход за пределы папки, внедрение в логи, утечка данных, обход ограничений на команды. Всё это обычные фаззеры, которые ищут падения, не заметили бы, потому что инструмент отрабатывал штатно. Отдельно авторы показали атаку Repeat-After-Me на шести оркестраторах: LangGraph, MAF, ADK 2.0, AutoGen, Strands и CrewAI. Во всех текст «повтори дословно» с вызовом инструмента превращался в реальный вызов.
Удивляет масштаб: проблема не редкая, а типичная. Практический инсайт: «модель вежливая и осторожная» ничего не гарантирует, если инструмент за ней не проверяет входные данные. (Текст статьи в материале обрезан: детали по классам багов и экспериментам не видны.)
Адаптации и экстраполяции
🔧 Техника: добавить Repeat-After-Me в красные флаги ревью агента → видеть слабые места раньше
Это не метод статьи, а вывод из неё. Перед тем как давать агенту доступ к инструментам с побочными эффектами (запись, удаление, отправка), спросите:
Если пользователь или документ, который читает агент, попросит «повторить дословно» текст в формате вызова инструмента, что произойдёт? Какие вызовы агент может сделать без моего подтверждения? Перечисли инструменты с побочными эффектами и предложи, для каких из них включить ручное подтверждение.Эффект: вы получаете список инструментов, где нужен человек в цепочке. Это догадка по мотивам статьи, не проверенная авторами защита.
🔧 Техника: убрать запрет на вердикт → быстрая оценка рисков
Удалите из шаблона строку «Не выноси вердикт» и добавьте «Оцени риск каждого аргумента: низкий / средний / высокий и объясни почему». Получите приоритизацию, но помните: это мнение модели, а не результат наблюдения за поведением инструмента.
Ресурсы
- Работа: ToFu: Exploiting and Fuzzing the LLM–Orchestrator–Tool Trust Boundary
- Авторы: Md Nazmul Islam Ananto, Colin Smith, Taegyu Kim, Arslan Khan (Pennsylvania State University); Pierre Prevost-Avenel (Université Montpellier); Kyungtae Kim (Dartmouth College)
- Упомянутые инструменты и работы: Atheris (фаззер Python), CWE (каталог классов уязвимостей), Cisco MCP Scanner, MCP-Scanner, ToolFuzz, VIPER-MCP, DCIChecker, MCPSecBench, CodeQL
- Оркестраторы, на которых воспроизвели Repeat-After-Me: LangGraph, MAF, ADK 2.0, AutoGen, Strands, CrewAI
