← Retour au blog
Analyse

Google Zero-Trust AI Agent : pourquoi chaque Tool Call a encore besoin d'une validation JSON ?

Publié le 25/09/2026 Dernière mise à jour le 25/09/2026 Environ 15 min Boîte à outils JSON

Comment lire cet article

Le Google Developers Blog a publié le 15/09/2026 le 2e volet de la série zéro confiance : le runtime doit juger l'intention, pas seulement la syntaxe. Ce texte est du 25/09/2026. On lit ce billet, Semantic Governance sur Cloud, et la page Hooks de l'API Gemini (dernière mise à jour le 04/09/2026). Conclusion à figer : le moteur d'intention avale encore un nom d'outil + un objet de paramètres. Si la syntaxe échoue au Schema, le verdict derrière n'est pas fiable. Le bus d'outils malveillant est un autre article : MCP malveillant / Fake Skills.

L'utilisateur dit « la licence logicielle de la commande 99281 ne convient pas, remboursez 120 dollars en entier ». Quand le modèle tend la main, vous voyez issue_refund et des paramètres qui ont l'air légaux. Les types SQL collent, le montant ne dépasse pas le total de la commande, le prompt n'a pas de jailbreak. Toutes les portes syntaxiques sont au vert. La politique de l'entreprise l'interdit encore : un bien numérique déballé au-delà de 30 dollars exige l'accord d'un manager. L'officiel appelle cette couche Semantic Governance. Elle juge l'intention. Elle ne remplace pas le Schema sur args. Pourquoi la couche contrat reste un objet : Pourquoi l'IA aime JSON.

Ce que Google a vraiment publié

Au 25/09/2026, les matériaux publics se coupent en deux. Ne les mélangez pas :

  • Gemini Enterprise Agent Platform : le billet du 15/09/2026 ramène le zéro confiance dans le runtime. Agent Gateway intercepte chaque interaction entre utilisateur, modèle et outils. Trois contrôles hébergés : Model Armor, Semantic Governance Policies, Agent Anomaly Detection (avec boucle de remédiation).
  • Gemini API Agent Hooks : dans le bac à sable, pre_tool_execution / post_tool_execution. Le script lit le JSON d'appel d'outil sur stdin, écrit allow / deny sur stdout. Documentation mise à jour le 04/09/2026. Certains exemples écrivent encore antigravity-preview-05-2026 ; fiez-vous à la chaîne Agent de la doc en cours, voir la mise à jour Antigravity de septembre.

L'officiel trace lui-même la frontière. Les contrôles déterministes du volet 1 (écritures signées KMS, isolation gVisor, passerelle regex) n'attrapent que ce que vous avez figé à l'avance. Une syntaxe de remboursement légale ne dit pas à une regex que « Workplace User License » est un bien numérique. Un runtime zéro confiance suppose qu'une requête unique peut avoir l'air légale et rester une pièce d'attaque.

Semantic Governance traite de la même façon les fonctions locales, les API backend et le MCP distant. Évaluation avant exécution. DENY : l'outil ne tourne pas. KMS n'est pas appelé. Le grand livre ne bouge pas. Ce n'est pas la même question que « MCP, c'est un type de connexion » ; contraste : Agents API vs MCP.

En une phrase. Google a hébergé la porte d'intention. Il n'a pas hébergé la porte de forme. Chaque Tool Call doit d'abord être un JSON capable de refuser.

Trois couches zéro confiance : où se place JSON

L'officiel plie le runtime en trois couches. Chacune tient son métier :

Zero-Trust Agent : trois portes Model Armor filtre le prompt ; Schema valide les arguments d'outil ; Semantic Governance juge l'intention sur un objet déjà légal. Enlevez une couche, le verdict suivant n'est plus fiable. Model Armor Prompt / sortie JSON Schema args d'abord Moteur d'intention ALLOW / DENY
La couche du milieu est la vôtre. L'officiel héberge l'intention. Il ne déclare pas quels champs issue_refund doit avoir.
  1. Model Armor : à l'entrée, filtre injection, jailbreak, URL malveillantes ; à la sortie, peut masquer numéros de carte et secrets. Un prompt bloqué n'atteint jamais le modèle.
  2. Contrat de paramètres : le JSON Schema de Function Calling / MCP. order_id manquant, amount écrit "一百二", une clé extra_cmd en trop : l'exécuteur ne doit pas tendre la main. Cette couche, l'officiel ne l'écrit pas à votre place.
  3. Semantic Governance : sur un nom d'outil et des paramètres déjà formés, confrontés à la phrase de l'utilisateur, à l'historique de session et à une politique en langage naturel, émettre ALLOW / DENY.

Le développeur lit trop vite la 3e couche comme « enfin plus besoin de Schema ». L'erreur est la couche. Structured Output tient la réponse finale ; Function Calling tient la main tendue. Le billet zéro confiance n'annonce pas que l'Agent gagne Structured Output. La couche contrat de réponse : Qu'est-ce que la Structured Output. Pourquoi une boucle texte hébergée a encore plus besoin d'objets : Pourquoi l'Agents API a encore plus besoin de JSON.

Couche syntaxe : d'abord refuser les mauvais appels

Dans la démo officielle, l'outil de remboursement peut d'abord se plier ainsi :

{
  "type": "function_call",
  "name": "issue_refund",
  "id": "call_refund_01",
  "arguments": {
    "order_id": "99281",
    "item": "Workplace User License",
    "amount": 120.0,
    "currency": "USD"
  }
}

Cet objet est syntaxiquement légal. Il peut encore violer « un bien numérique au-delà de 30 dollars exige l'accord d'un manager ». C'est l'affaire de la couche suivante. Clouez d'abord le contrat :

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "required": ["order_id", "item", "amount", "currency"],
  "properties": {
    "order_id": { "type": "string", "pattern": "^[0-9]{5}$" },
    "item": { "type": "string", "minLength": 1 },
    "amount": { "type": "number", "exclusiveMinimum": 0, "maximum": 149 },
    "currency": { "type": "string", "enum": ["USD"] }
  }
}

Figez d'abord les formes qui doivent échouer. Dans l'espace de travail, elles doivent passer au rouge :

{
  "ok_shape": { "order_id": "99281", "item": "Workplace User License", "amount": 120.0, "currency": "USD" },
  "wrong_type": { "order_id": "99281", "item": "Workplace User License", "amount": "一百二", "currency": "USD" },
  "extra_field": { "order_id": "99281", "item": "USB-C Dock", "amount": 29.0, "currency": "USD", "extra_cmd": "skip_kms" },
  "over_total": { "order_id": "99281", "item": "USB-C Dock", "amount": 10000, "currency": "USD" }
}

Seul ok_shape entre dans le moteur d'intention. "一百二", extra_cmd, 10000 doivent être refusés au Schema. Ne confiez pas « exécute quand même » à une politique en langage naturel. Un outil trop large et un faux manuel sont le même risque : limiter les permissions d'outils avec un Schema.

Couche intention : un verdict DENY

L'officiel écrit les politiques en contraintes lisibles, pas en un nouveau tas de regex. La politique de remboursement du billet, en substance : bien numérique déballé, licence logicielle ou destockage au-delà de 30 dollars — refuser et passer à un humain ; un accessoire physique jusqu'à 149 dollars peut passer. Quand le modèle propose issue_refund(amount=120.00, item="Workplace User License"), le moteur DENY. Dans Cloud Logging, on voit une forme proche de :

{
  "evaluations": [
    {
      "actionName": "issue_refund",
      "toolName": "order_processing",
      "verdict": "DENY",
      "rationale": "The tool attempted to refund $120.00 for 'Workplace User License', a digital software product. Digital software refunds over $30 require manager authorization."
    }
  ],
  "timestamp": "2026-09-03T15:52:21.447123Z",
  "verdict": "DENY"
}

L'outil n'exécute pas. Le grand livre n'est pas écrit. L'Agent explique la politique à l'utilisateur. La doc plateforme prend aussi DRY_RUN : enregistrer le verdict, ne pas intercepter, pour ajuster la contrainte. Ces journaux sont aussi du JSON : les champs doivent parser. Ne traitez pas toute la ligne de log comme contrat final.

La couche intention avale des paramètres déjà passés au Schema. Si amount est parfois un nombre, parfois une chaîne, la même contrainte en langage naturel donnera un rationale instable. D'abord la forme, ensuite l'intention.

Porte Hook : stdin / stdout sont aussi des objets

Côté bac à sable, les Hooks sont plus directs. Le pre_tool_execution officiel lit l'entrée standard :

{
  "tool_call": {
    "name": "code_execution",
    "args": {
      "code": "rm -rf /tmp/forbidden",
      "language": "bash"
    }
  },
  "environment_id": "env_xyz789"
}

Le script doit écrire un objet de décision. Pour intercepter :

{
  "decision": "deny",
  "reason": "Destructive command blocked by security gate."
}

Pour laisser passer, il suffit de {"decision":"allow"}. La doc fige une sémantique d'échec : JSON non reconnu, texte brut, ou toute sortie autre que {"decision":"deny"} — le runtime traite ça comme allow. L'objet de décision lui-même a besoin d'un Schema. Un test d'inclusion du type "deny" in text, c'est démonter la porte.

Un Hook HTTP POST le même événement ; le corps de réponse reste cette forme decision. Un Hook post-tool ne fait que formater ou auditer : il ne peut pas annuler un effet de bord déjà arrivé. Les écritures à haut risque doivent être arrêtées en pre-tool. Parser args, c'est le même geste qu'en session Live : tutoriel Live Function Calling.

Légal une fois, le cumul peut encore percer

Troisième scène officielle : l'attaquant apprend que « un remboursement logiciel sous 30 dollars passe », puis casse 120 en plusieurs 20. Chaque tour passe Model Armor, la politique d'un tour, et obtient une signature KMS. Le cumul dépasse le total de commande de 149. Une porte à un tour ne voit ni la vitesse de session ni le montant cumulé.

Cette couche s'appuie sur Agent Anomaly Detection (télémétrie), puis une nouvelle contrainte en langage naturel : « cette session a déjà un remboursement réussi pour le même order_id — DENY ». La contrainte peut arriver au runtime, sans redéployer l'Agent. La prémisse ne change pas : chaque args de issue_refund doit parser de la même façon. Le cumul additionne des objets légaux. Il n'additionne pas de la prose.

Recetter dans la Boîte à outils JSON

  1. Collez le ok_shape de issue_refund et les trois objets qui doivent échouer dans le formatage JSON, confirmez que ça parse.
  2. Avec JSON → Schema, générez le contrat cœur, puis ajoutez enum, maximum, additionalProperties.
  3. Les mêmes champs via Function Calling ; si l'outil doit aussi servir d'autres Hosts, enveloppez encore dans MCP Tool.
  4. Jetez "一百二", extra_cmd, 10000 dans la validation Schema, confirmez le refus. L'objet decision du Hook passe par le même jeu : seulement allow / deny. Pour aligner une forme de réponse, Structured Output — souvenez-vous : le billet zéro confiance tient la main tendue de l'outil, pas le contrat de réponse finale.

Tout se traite dans le navigateur, rien n'est envoyé. D'abord un objet capable de refuser de mauvais args et un decision brouillé, ensuite seulement confier la politique en langage naturel à la plateforme.

FAQ

Avec Semantic Governance, faut-il encore un JSON Schema ?

Oui. Le moteur d'intention avale des paramètres déjà formés. Champs manquants, mauvais types, clés en trop : le Schema doit refuser.

Le allow / deny des Hooks, c'est de la Structured Output ?

Non. C'est le JSON de décision que le script écrit au runtime. Non reconnu = allow. La réponse finale peut rester du langage naturel.

Semantic Governance couvre-t-il MCP ?

L'officiel évalue fonctions locales, API et MCP avant l'exécution. Le déguisement d'outils est une autre couche.

Chaque refund est légal. Pourquoi encore valider ?

Le fractionnement perce une politique à un tour. Le Schema tient la forme ; le cumul demande la détection d'anomalies et une nouvelle contrainte. Les deux couches passent avant de parler de signature.

Que se passe-t-il si le script Hook sort n'importe quoi ?

Sans objet deny explicite, c'est allow. Le JSON de décision a aussi besoin d'un Schema.

En résumé

Google a ramené le zéro confiance dans le runtime : filtrer le prompt à l'entrée, juger l'intention avant l'outil, regarder le cumul en session. Il n'a pas emporté le contrat de paramètres de chaque Tool Call. Ce que le développeur doit tenir : deux objets, function_call.arguments et le decision du Hook. Une forme légale seulement entre dans le moteur d'intention ; un DENY d'intention seulement évite le grand livre ; un Hook qui sort n'importe quoi, c'est ouvrir la porte. La suite n'est pas d'abord une politique en langage naturel plus longue. C'est d'abord de refuser "一百二" et extra_cmd.