Блог • Agent Security

Почему AI-агенту нельзя доверять только JSON Schema: проверка, недоверенный ввод и решение о правах

Вызов инструмента, прошедший JSON Schema, показывает только верную форму аргументов. Письмо, изменение файла или выход наружу требуют второго JSON: решения о правах. Если decision не allow, вызов останавливается.

Зачем выводу нужна форма — в статье зачем ИИ нужен JSON Schema. Кто отвечает за безопасность при многих серверах инструментов — в статье безопасность и права MCP. Здесь только решение после верной формы: список разрешённых, grant и allow / deny / ask.

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

Что доказывает схема

JSON Schema проверяет типы, enum и обязательные ключи. См. JSON Schema. Она не доказывает, что этой сессии можно отправлять почту, и не доказывает, что вы проверяли это имя инструмента.

Три поля, все строки. Такой вызов может пройти схему аргументов и всё равно не должен уходить.
{
  "tool": "send_email",
  "arguments": {
    "to": "ops@example.com",
    "subject": "status",
    "body": "ok"
  }
}

Когда to, subject и body — строки, схема аргументов видит только типы. Она не видит, что grant этой сессии содержит read_inbox и не содержит send.

Решение — другой JSON

Спецификация инструментов MCP требует проверки ввода и возможности человеку отказать в вызове. См. MCP Tools. После того как JSON аргументов прошёл, запишите решение. toolAllowed значит, что это имя инструмента есть в вашем списке. grant — способность, которая у сессии уже есть. decision может быть только allow, deny или ask.

Форма аргументов верна, инструмент в списке. Но grant содержит только чтение почты. decision равен deny.
{
  "tool": "send_email",
  "argumentsValid": true,
  "toolAllowed": true,
  "grant": ["read_inbox"],
  "decision": "deny",
  "reason": "grant_missing"
}
Решение — в первое поле, эту схему — во второе. действовать переключите на Проверьте с помощью Schema.
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["tool", "argumentsValid", "toolAllowed", "decision", "reason"],
  "properties": {
    "tool": { "enum": ["send_email"] },
    "argumentsValid": { "type": "boolean" },
    "toolAllowed": { "type": "boolean" },
    "grant": {
      "type": "array",
      "items": { "enum": ["read_inbox", "send"] }
    },
    "decision": { "enum": ["allow", "deny", "ask"] },
    "reason": {
      "enum": ["ok", "grant_missing", "tool_not_allowlisted", "arguments_invalid"]
    }
  }
}

Эта схема останавливает decision вне трёх значений, argumentsValid не булева типа, отсутствие decision и значение grant вне списка. Она не может сказать, что allow требует одновременно toolAllowed и нужный grant. Эти правила остаются в приложении.

Прохождение, которое всё равно отклоняют

Измените решение выше: decision равен allow, reason равен ok, grant остаётся read_inbox. Эта схема проходит. Прохождение — не разрешение отправить письмо. Правило приложения: decision может быть allow только если argumentsValid и toolAllowed оба true и grant содержит send. Если чего-то нет, верните deny или ask и не вызывайте инструмент.

Правило в приложенииВидит ли это схема?Если не выполнено
при allow argumentsValid должен быть trueЭту связку она не видитПоставить deny, reason равен arguments_invalid
при allow toolAllowed должен быть trueЭту связку она не видитПоставить deny, reason равен tool_not_allowlisted
при allow в grant должен быть sendЭту связку она не видитПоставить deny или ask, reason равен grant_missing

Где останавливаются три случая

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

СлучайКакой может быть формаГде остановить
Форма аргументов невернаСхема не проходитНе писать allow и не вызывать
Инструмента нет в списке разрешённыхАргументы всё ещё могут быть вернымиtoolAllowed равен false, decision равен deny
У сессии нет этой способностиАргументы верны, инструмент в спискеВ grant нет способности, значит deny или ask

Недоверенный текст может привести к тому, что модель предложит вызов, а недоверенное описание инструмента может показать опасную способность как обычный инструмент. И то и другое может дать JSON верной формы. Защита не в том, чтобы воспроизвести этот текст. Сначала внесите инструмент в список разрешённых, прогоните вызов через схему, затем по grant выберите allow, deny или ask. Человек по-прежнему может отказать в вызове.

Чем эта статья отличается от других

Зачем нужна схемаКто отвечает за безопасность MCPЭта статья
ОтвечаетЗачем выводу нужна формаКто отвечает, когда серверов многоКакой JSON прав ещё нужен после верной формы
Здесь не ищитеЕщё одно введение в схемуКто в организации подписываетШаги атаки, которые можно повторить

Остановить неверный allow в JSONNote

  1. 1
    Выбрать нужную операцию

    Откройте JSON Schema. Переключите действовать на Проверьте с помощью Schema. Решение о правах — в первое поле, схему выше — во второе. decision может быть только allow, deny или ask. Каждый элемент grant — только read_inbox или send.

  2. 2
    Прогнать четыре плохих документа

    Поставьте decision равным yes, argumentsValid — строке true, удалите decision или поставьте grant равным send_all. Все четыре не проходят. decision allow, reason ok и grant read_inbox проходит. После этого верните deny или ask и не вызывайте инструмент.

  3. 3
    Сравнить deny и allow

    Откройте JSON Сравнить Diff. В первое поле — решение deny. Во втором поменяйте только decision на allow и reason на ok. grant остаётся read_inbox. Оба проходят схему. Отправку останавливает правило приложения, а не эта проверка формы.

Вопросы

Можно ли выполнять инструмент, как только схема прошла?

Нет. Схема доказывает только форму аргументов. Ещё проверьте, есть ли инструмент в списке и содержит ли grant эту способность. Если решение не allow, инструмент не вызывайте.

Если решение о правах прошло свою схему, можно ли поставить allow?

Не из этого одного. decision allow, reason ok и grant только с read_inbox — всё ещё верная форма. Приложение ещё должно увидеть toolAllowed true и нужную способность в grant. Если чего-то нет, это не allow.

Что здесь значат prompt injection и tool poisoning?

Это названия двух рисков, а не шаги, которые эта статья воспроизводит. Один — недоверенный текст, из-за которого модель предлагает вызов. Другой — недоверенное описание инструмента, из-за которого опасная способность выглядит обычной. Оба могут дать JSON верной формы. Их останавливают список разрешённых, схема и grant, а не переписывание этого текста.

Это та же статья, что про необходимость JSON Schema?

Нет. Те статьи объясняют, зачем выводу нужна форма. Эта начинается после того, как форма уже прошла: список разрешённых и grant всё ещё могут сделать decision равным deny или ask.

В чём разница между ask и deny?

deny значит не вызывать в этот раз. ask значит сначала показать аргументы человеку; если человек отказывает, всё равно не вызывать. Оба не равны allow. Человек в контуре — это способность отказать, записанная в спецификации инструментов MCP.

Итог

JSON Schema останавливает аргументы инструмента с неверной формой. Решение о правах останавливает вызов, форма которого уже верна, а способность — нет. Храните оба JSON, и у выполнения появляется ворота.

Решение: прохождение схемы значит только верную форму; сначала внесите инструмент в список; grant должен содержать эту способность; если decision не allow, не вызывайте; если decision равен allow, а grant недостаточен, смените на deny или ask, даже когда форма прошла.

Дальше: прогоните решение о правах через схему, затем проверьте, разрешает ли grant этот allow.

Назад в блог