Blog • Agent Security

Pourquoi un agent IA ne peut pas se fier au seul JSON Schema : validation, entrée non fiable, décision de permission

Un appel d'outil qui passe JSON Schema montre seulement que les arguments ont la bonne forme. Envoyer un message, modifier un fichier ou sortir de la machine demande un second JSON : la décision de permission. Si decision n'est pas allow, l'appel s'arrête.

Pourquoi la sortie a besoin d'une forme : pourquoi l'IA a besoin de JSON Schema. Qui est responsable quand beaucoup de serveurs d'outils sont connectés : sécurité et permissions MCP. Cet article ne traite que la décision après une forme valide : liste autorisée, grant, et allow / deny / ask.

Retenez d'abord ceci : Un appel à la bonne forme peut rester un appel à ne pas exécuter. Ensuite : ce que le schéma prouve, à quoi ressemble la décision, un succès que vous refusez quand même, et où trois cas s'arrêtent.

Ce que le schéma prouve

JSON Schema vérifie les types, les enums et les clés requises. Voir JSON Schema. Il ne prouve pas que cette session peut envoyer un message, ni que vous avez revu ce nom d'outil.

Trois champs, tous des chaînes. Cet appel peut passer un schéma d'arguments et ne doit quand même pas partir.
{
  "tool": "send_email",
  "arguments": {
    "to": "ops@example.com",
    "subject": "status",
    "body": "ok"
  }
}

Quand to, subject et body sont des chaînes, un schéma d'arguments ne voit que les types. Il ne voit pas que le grant de cette session a read_inbox et pas send.

La décision est un autre JSON

La spécification des outils MCP exige une validation des entrées et un moyen pour une personne de refuser l'appel. Voir MCP Tools. Après un JSON d'arguments valide, écrivez une décision. toolAllowed signifie que ce nom d'outil est sur votre liste autorisée. grant est la capacité que cette session a déjà. decision ne peut être que allow, deny ou ask.

La forme des arguments est valide et l'outil est sur la liste. Le grant ne contient que la lecture du courrier. decision est deny.
{
  "tool": "send_email",
  "argumentsValid": true,
  "toolAllowed": true,
  "grant": ["read_inbox"],
  "decision": "deny",
  "reason": "grant_missing"
}
Collez la décision dans le premier champ et ce schéma dans le second. Réglez Fonctionnement sur Vérifiez avec 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"]
    }
  }
}

Ce schéma arrête une decision hors des trois valeurs, un argumentsValid qui n'est pas un booléen, une decision manquante et une valeur de grant hors liste. Il ne peut pas dire qu'allow exige à la fois toolAllowed et le grant nécessaire. Ces règles restent dans l'app.

Un succès que vous refusez

Changez la décision ci-dessus : decision à allow, reason à ok, grant reste read_inbox. Ce schéma passe. Réussir n'est pas une autorisation d'envoyer. La règle de l'app : decision ne peut être allow que si argumentsValid et toolAllowed sont tous deux true et si grant contient send. S'il en manque un, repassez à deny ou ask et n'appelez pas l'outil.

Règle dans l'appLe schéma le voit-il ?Si cela échoue
allow exige argumentsValid trueIl ne voit pas cette combinaisonMettre deny, reason arguments_invalid
allow exige toolAllowed trueIl ne voit pas cette combinaisonMettre deny, reason tool_not_allowlisted
allow exige send dans grantIl ne voit pas cette combinaisonMettre deny ou ask, reason grant_missing

Où trois cas s'arrêtent

Les annotations sur la description d'un outil sont des indices. La spécification dit que les annotations d'une source non fiable ne sont pas un contrôle de sécurité déjà appliqué. Voir les annotations d'outil ne sont pas un contrat. Ce qui arrête vraiment l'appel, c'est votre schéma et cette décision.

CasÀ quoi la forme peut ressemblerOù vous arrêtez
La forme des arguments est fausseLe schéma échoueNe pas écrire allow, et ne pas appeler
L'outil n'est pas sur la liste autoriséeLes arguments peuvent rester validestoolAllowed est false, decision est deny
La session n'a pas la capacitéArguments valides, outil sur la listeLe grant n'a pas la capacité, donc deny ou ask

Un texte non fiable peut amener un modèle à proposer un appel, et une description d'outil non fiable peut faire ressembler une capacité dangereuse à un outil ordinaire. Les deux peuvent produire un JSON de forme valide. La défense n'est pas de reproduire ce texte. Mettez d'abord l'outil sur la liste autorisée, faites passer l'appel par le schéma, puis utilisez le grant pour choisir allow, deny ou ask. Une personne peut encore refuser l'appel.

Ce que les autres articles couvrent

Pourquoi le schéma est nécessaireQui porte la sécurité MCPCet article
Répond àPourquoi la sortie a besoin d'une formeQui est responsable avec beaucoup de serveursQuel JSON de permission reste nécessaire après une forme valide
Ne cherchez pas iciUne nouvelle introduction au schémaQui signe dans l'organisationDes étapes d'attaque à recopier

Arrêter un allow incorrect dans JSONNote

  1. 1
    Choisir la bonne opération

    Ouvrez JSON Schema. Réglez Fonctionnement sur Vérifiez avec Schema. Collez la décision dans le premier champ et le schéma ci-dessus dans le second. decision ne peut être que allow, deny ou ask. Chaque entrée de grant seulement read_inbox ou send.

  2. 2
    Opposer quatre documents invalides

    Mettez decision à yes, argumentsValid à la chaîne true, supprimez decision, ou mettez grant à send_all. Les quatre échouent. decision à allow, reason à ok et grant à read_inbox passe. Ensuite, revenez à deny ou ask et n'appelez pas l'outil.

  3. 3
    Comparer deny et allow

    Ouvrez JSON Comparer Diff. Collez la décision deny dans le premier champ. Dans le second, changez seulement decision en allow et reason en ok. grant reste read_inbox. Les deux passent le schéma. C'est la règle de l'app qui arrête l'envoi, pas ce contrôle de forme.

Questions fréquentes

L'outil peut-il s'exécuter dès que le schéma passe ?

Non. Le schéma ne prouve que la forme des arguments. Vous vérifiez encore si l'outil est sur la liste autorisée et si le grant contient la capacité. Si la décision n'est pas allow, n'appelez pas l'outil.

Si la décision de permission passe son schéma, peut-on mettre allow ?

Pas sur ce seul point. decision allow, reason ok et un grant limité à read_inbox reste une forme valide. L'app doit encore voir toolAllowed true et la capacité nécessaire dans grant. S'il en manque un, ce n'est pas allow.

Que veulent dire prompt injection et tool poisoning ici ?

Ce sont les noms de deux risques, pas des étapes que cet article reproduit. L'un est un texte non fiable qui amène un modèle à proposer un appel. L'autre est une description d'outil non fiable qui fait paraître ordinaire une capacité dangereuse. Les deux peuvent donner un JSON de forme valide. Ce qui les arrête, c'est la liste autorisée, le schéma et le grant, pas la réécriture de ce texte.

Est-ce le même article que celui sur la nécessité de JSON Schema ?

Non. Ces articles expliquent pourquoi la sortie a besoin d'une forme. Celui-ci commence après une forme déjà valide : la liste autorisée et le grant peuvent encore faire de decision un deny ou un ask.

Quelle est la différence entre ask et deny ?

deny signifie ne pas appeler cette fois. ask signifie montrer d'abord les arguments à une personne ; si elle refuse, ne pas appeler non plus. Aucun des deux n'est allow. Une personne dans la boucle est la capacité de refus écrite dans la spécification des outils MCP.

Conclusion

JSON Schema arrête les arguments d'outil à la mauvaise forme. La décision de permission arrête un appel dont la forme est déjà bonne mais dont la capacité est fausse. Gardez les deux JSON, et l'exécution a une porte.

La décision : passer le schéma ne veut dire que la forme est bonne ; mettez d'abord l'outil sur la liste autorisée ; le grant doit contenir cette capacité ; si decision n'est pas allow, n'appelez pas ; si decision est allow mais le grant est insuffisant, passez à deny ou ask même si la forme est valide.

Ensuite : faites passer la décision de permission par le schéma, puis voyez si le grant autorise cet allow.

Retour au blog