3,583 papers
arXiv:2610.13651 74 9 окт. 2026 г. FREE

ToFu: проверка MCP-инструментов агента через их же описания, а не через атаку на модель

КЛЮЧЕВАЯ СУТЬ
Обнаружено: инструмент, который вы подключаете к агенту, почти никогда не проверяет то, что сам обещает в описании. В 118 из 273 открытых MCP-серверов (протокол подключения инструментов к агенту) нашлись нарушения. Метод ToFu позволяет заранее составить план проверки чужого сервера — какие значения подсунуть и что наблюдать. ToFu превращает описание аргумента в проверку: «файл внутри рабочей папки» значит «путь не должен выходить за папку». Затем он пробует это нарушить и смотрит на реальное поведение инструмента: какой файл открылся, какой адрес запрошен. Падения нет, ошибки нет, а файл из любой папки отдан.
Адаптировать под запрос
⚡

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

📋 Дайджест исследования

Ключевая суть

Обнаружено: инструмент, который вы подключаете к агенту, почти никогда не проверяет то, что сам обещает в описании. В 118 из 273 открытых MCP-серверов (протокол подключения инструментов к агенту) нашлись нарушения. Метод ToFu позволяет заранее составить план проверки чужого сервера — какие значения подсунуть и что наблюдать. ToFu превращает описание аргумента в проверку: «файл внутри рабочей папки» значит «путь не должен выходить за папку». Затем он пробует это нарушить и смотрит на реальное поведение инструмента: какой файл открылся, какой адрес запрошен. Падения нет, ошибки нет, а файл из любой папки отдан.

Принцип работы

Принцип простой: описание = обещание, а обещание нужно попытаться сломать. Обычная проверка ищет падения. Здесь их нет. Инструмент отработал «успешно» и отдал лишнее. Поэтому тип аргумента «строка» ничего не говорит. Путь, адрес и команда требуют разных защит. Процесс такой: прочитать описание → понять, что за аргумент (путь, адрес, команда) → вывести обещание → подобрать «злые» значения вроде ../../etc/passwd или внутренних адресов → запустить и смотреть, что инструмент реально сделал. Вердикт выносит не модель, а наблюдение за поведением инструмента. Модель только сопоставляет описание с набором проверок. Судья из неё никакой.

Почему работает

Смысл аргумента уже записан словами, и модель хорошо превращает такие фразы в проверки. Описание — это готовое требование, его не надо придумывать с нуля. Корпус из 74 проверок по классам уязвимостей (CWE) и 21 трассировщик (записывают обращения к файлам, процессам, сети) делают остальное. Есть и вторая находка, она неприятнее. Атака Repeat-After-Me: просишь модель «повторить дословно» текст, похожий на вызов инструмента. Жесть — модель просто повторила текст, а оркестратор (слой, который превращает ответ модели в запуск инструмента) принял его за команду и запустил с вашими аргументами. Вывод: аргументы, которые написала модель, нельзя считать безопасными. Запрет в промпте вроде «не выходи за папку» не заменяет проверку пути внутри самого инструмента.

Когда применять

Безопасность агентов → выбор и подключение чужого MCP-сервера, особенно когда рядом лежат договоры, ключи или выгрузки с данными. Метод даёт аналитику или менеджеру список того, что проверить с разработчиком. Работает лучше всего, когда описания аргументов точные («только *.csv в ~/work/sales»). НЕ подходит как ответ на вопрос «этот сервер безопасен?». Модель выдаст догадку, а не проверку. Настоящий ToFu — это код на Python с фаззером (программой, которая бросает в инструмент странные значения). В одном чате его не воспроизвести. Расплывчатое или пустое описание тоже ломает метод: нечего проверять.

Мини-рецепт

1. Собери описания: возьми названия, описания и аргументы инструментов из конфига сервера или его README.
2. Опиши среду: где работает агент, какие у него права, что ценное лежит рядом.
3. Запроси план, а не оценку: для каждого аргумента — смысл, обещание, 5 злых значений, что наблюдать.
4. Запрети вердикт: прямо напиши «не выноси вердикт безопасно/небезопасно».
5. Дай место неясному: где описание расплывчатое, пусть модель пишет «неясно» и задаёт вопрос автору сервера.
6. Тестируй на копии: прогони злые значения на тестовой копии папки, не на рабочей.
7. Смотри на поведение: какой файл открылся, куда ушёл запрос. Отсутствие ошибки безопасностью не считай.

Примеры

[ПЛОХО] : Оцени, безопасен ли этот MCP-сервер для работы с файлами
[ХОРОШО] : Ты помогаешь составить план проверки инструментов MCP-сервера. Не выноси вердикт «безопасно», только план. Инструмент: read_file(path: string) — «Читает файл внутри рабочей папки ~/work/sales». Рядом лежат договоры с поставщиками. Для аргумента path выведи: что он означает по описанию, какое свойство безопасности из этого следует, 5 злых значений, которые проходят по типу string, и что наблюдать, чтобы доказать нарушение. В конце — 3 вопроса автору сервера, на которые нет ответа в описании. Модель вернёт таблицу: свойство «путь остаётся внутри ~/work/sales», злые значения вроде ../../contracts/supplier.pdf, наблюдение «какой файл реально открыт». Первый запрос даст отписку. Второй даст чек-лист, который можно отнести разработчику.
Источник: ToFu: Exploiting and Fuzzing the LLM-Orchestrator-Tool Trust Boundary
ArXiv ID: 2610.13651 | Сгенерировано: 2026-10-12 06:40

Проблемы LLM

ПроблемаСутьКак обойти
Слово «повтори дословно» запускает инструмент у агентаАгент превращает ответ модели в вызов инструмента. Этим занимается слой-оркестратор. Пользователь просит: «повтори дословно» и даёт текст, похожий на вызов инструмента. Модель честно повторяет. Оркестратор видит в ответе вызов и запускает его с аргументами пользователя. Модель ничего не «взломали». Она просто выполнила безобидную просьбуНе доверяй аргументам, которые пришли через модель. Проверяй их в самом инструменте: путь внутри папки, адрес из разрешённого списка. Не полагайся на фразу в промпте «не выходи за папку». Оркестратору не давай запускать вызовы из цитат и повторённого текста. Различай «модель решила вызвать» и «модель процитировала»

Методы

МетодСуть
Из описания — обещание, из обещания — попытка нарушитьБерёшь описание любого инструмента, функции или API. Просишь модель выделить из него обещание. Например, «читает файл внутри папки» значит «путь не выходит за корень». Затем модель придумывает «злые» значения. Они проходят по типу (строка), но нарушают обещание. Например, ../../etc/passwd. Для каждого значения модель называет наблюдение, которое докажет нарушение: какой файл открыт, какой адрес запрошен. Шаблон запроса: Для КАЖДОГО аргумента: 1) что он значит по описанию; 2) какое свойство безопасности следует; 3) 5 злых значений, проходящих по типу; 4) что наблюдать как доказательство; 5) если описание расплывчатое — пометь «неясно» и задай вопрос автору. Вердикт «безопасно» не выноси. Почему работает: тип «строка» ничего не говорит о смысле. Смысл лежит в тексте описания, и модель хорошо переводит такие фразы в проверки. Вердикт выносит наблюдение за реальным поведением, а не догадка модели. Когда да: до подключения чужого сервера инструментов (MCP), при разборе API, при проверке функций с входом от пользователя. Когда нет: описание пустое или двусмысленное. Тогда выйдут только вопросы. План надо прогонять вручную или кодом на тестовой копии данных, не на рабочей. Сама модель ничего не проверит
📖 Простыми словами

ToFu: Exploiting and Fuzzing theLLM-Orchestrator-ToolTrust Boundary

arXiv: 2610.13651

Когда AI-ассистент вызывает внешние тулы, между ними возникает опасная слепая зона доверия. Для системы любой аргумент функции — это просто банальная строка, будь то безобидное имя файла, закрытый IP-адрес или системная команда. Разработчик пишет в описании тула: "читает файлы строго из папки проекта", LLM наивно верит этому тексту, а сам инструмент молча выплевывает наружу системные логи. При этом сервер не падает с ошибкой, код отдает статус 200, и всем кажется, что всё работает штатно.

Это как охранник в клубе, у которого в правилах написано пускать только людей в смокингах, но на фейсконтроле он проверяет лишь сам факт наличия ткани на теле. Пришел чувак в рваных трениках — охранник ставит галочку «проверка пройдена» и распахивает дверь, ведь формально гость не голый. Система не зависает, сирена не воет, а внутри уже творится полный хаос.

Новый фреймворк ToFu вскрывает эту лажу через семантический фаззинг. Он парсит текстовое описание инструмента, вытаскивает наружу каждое честное слово разработчика и целенаправленно генерирует под него ядовитые входные данные. Скрипт скармливает аргументам пути вроде ../../etc/passwd, долбится во внутреннюю сеть и сует шелл-инъекции. Модель здесь не работает наивным судьей — она лишь составляет карту проверок, а софт жестко фиксирует факт: инструмент нарушил собственное обещание.

Тестировали на базовых агентах, но принцип универсален для любой модульной архитектуры, включая новомодные MCP-серверы и кастомные плагины. Если ты подключаешь к модели сторонний API, нельзя верить его документации на слово. Тот же подход позволяет выстроить автоматический аудит до деплоя: скормил описания тулов генератору тестов, прогнал атаки и сразу увидел, где чужой код втихую сливает секреты мимо валидации.

Главный вывод: если тул выполнил запрос без пятисотой ошибки — это вообще не значит, что он безопасен. Хватит молиться на «здравый смысл» промптов и надеяться на авось. Внедряй проверку смысловых границ в свой CI/CD пайплайн прямо сейчас, иначе твой продвинутый агент станет главной отмычкой для хакера.

Работа с исследованием

Адаптируйте исследование под ваши задачи или создайте готовый промпт на основе техник из исследования.

0 / 2000
~0.5-2 N-токенов ~10-30с
~0.3-1 N-токенов ~5-15с