Pourquoi les agents de code IA ont besoin d’un contrôle de permissions : Shell, Git et système de fichiers en JSON (2026)
Le texte sécurité a déjà couvert la surface d’attaque. Celui-ci ne traite que le modèle de permissions : un appel d’outil est un JSON ; l’exécution reste chez l’hôte. Shell, Git et le système de fichiers sont trois portes. Cliquer Autoriser n’est pas fermer le bac à sable.
Avant de lire
| Porte | Ce qu’elle verrouille | Qui exécute |
|---|---|---|
| Shell | Chaînes de commande, commandes composées | allow / ask / deny ; bac à sable à part |
| Git | status, diff, commit, push ; hooks / config | Écrire l’espace de travail ≠ écrire les métadonnées |
| Système de fichiers | src, .env, chemins hors espace de travail | Règles d’outil + bac à sable OS |
| Réseau | Domaines, sortant | Fermé par défaut ; ouvrir une liste |
L’hôte évalue la politique. Le modèle remplit du JSON. Il ne déplace pas la porte.
Le contrôle de permissions existe parce que le modèle n’exécute pas
Quand un agent de code appelle un outil, le modèle n’émet que du JSON : un nom et des arguments. C’est l’hôte qui lance git status ou modifie src/orders/A-1042.json. Schema verrouille la forme. La politique verrouille si un appel bien formé peut tourner. Sans la seconde porte, la première n’est que de la politesse.
- Schema : verrouiller les arguments. Une commande est une chaîne. Un chemin reste sous un préfixe convenu.
- Politique de permissions : allow / ask / deny. L’ordre officiel est deny, puis ask, puis allow. Un allow étroit ne perce pas un deny large.
- Bac à sable : une couche OS. Si une injection oriente le modèle, le processus ne quitte pas l’espace de travail. Un clic d’approbation n’ouvre pas le bac à sable.
Comment le JSON d’outil se remplit : Agents de code IA et appels d’outils JSON. Comment on collecte la surface d’attaque : Crise de sécurité des agents et validation JSON. Pourquoi Schema est une porte : Pourquoi l’IA a besoin de JSON Schema. Ce texte ne répète pas les trois. Il pose seulement Shell, Git et fichiers en objets.
L’objet de permissions : allow, ask, deny
Claude Code écrit les règles sous permissions dans settings.json. L’hôte les évalue, pas le modèle. CLAUDE.md change ce que Claude tente. Pas ce que Claude Code autorise. Dépôt fictif — pas de secrets réels :
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git diff *)",
"Bash(npm test *)",
"Read(./src/**)",
"Edit(./src/**)"
],
"ask": [
"Bash(git commit *)"
],
"deny": [
"Bash(git push *)",
"Read(./.env)",
"Edit(./.git/hooks/**)",
"Edit(./.git/config)"
]
}
}
Un nom d’outil nu comme Bash en deny retire l’outil du contexte. Une règle entre parenthèses bloque les appels correspondants et laisse l’outil. Les commandes composées se matchent par sous-commande : autoriser git status n’autorise pas une seconde commande derrière. Codex utilise des profils (:workspace / :read-only) et ne les mélange pas avec l’ancien sandbox_mode. Cursor utilise une liste de préfixes dans permissions.json, plus sandbox.json.
Première porte : Shell
Le modèle tend une chaîne de commande. L’hôte confronte la politique avant d’exécuter. Une consultation en lecture passe souvent :
{
"type": "tool_use",
"id": "call_7f2a",
"name": "Bash",
"input": {
"command": "git status"
}
}
Dans la même politique, un push distant est deny. L’objet est bien formé. L’exécution reste chez l’hôte. La liste terminal de Cursor matche des préfixes : git couvre git status. La doc officielle dit aussi que les Run Modes sont des garde-fous de meilleur effort, pas une frontière dure. Pour une frontière dure, activer le bac à sable.
{
"type": "tool_use",
"id": "call_8a01",
"name": "Bash",
"input": {
"command": "git push origin main"
}
}
Deuxième porte : Git n’est pas une écriture disque ordinaire
Un espace de travail inscriptible n’est pas un .git inscriptible. Sous les racines inscriptibles, Codex garde .git, .agents et .codex en lecture seule par défaut ; si .git est un pointeur gitdir:, le répertoire résolu est protégé aussi. Le bac à sable de Claude Code laisse un worktree écrire assez dans le .git partagé pour committer, et refuse encore hooks/ et config. Cursor protège de même .git/hooks et .git/config. Un push bloqué doit laisser un objet :
{
"tool": "Bash",
"command": "git push origin main",
"eval_order": ["deny", "ask", "allow"],
"matched": "Bash(git push *)",
"rule": "deny",
"sandbox": "workspace-write",
"execute": false
}
En échec, renvoyer un tool_result qui nomme la règle. Ne pas toucher le distant en silence. Mettre commit en ask : une personne voit le diff. Mettre push en deny, sauf si cette session est explicitement une publication.
{
"type": "tool_result",
"tool_use_id": "call_8a01",
"is_error": true,
"content": "denied by policy: Bash(git push *)"
}
Troisième porte : le système de fichiers a besoin de deux couches
Une couche, les règles d’outil. L’autre, le bac à sable OS. La doc officielle les sépare parce qu’elles arrêtent des appels différents :
- Règles d’outil : le deny Read / Edit de Claude couvre les outils fichiers intégrés et des commandes reconnues comme
cat/head. Un script de langage qui ouvre des fichiers lui-même est hors de cette couche. - Bac à sable OS : une frontière de processus. Les écritures par défaut restent dans le répertoire de travail et le temp de session. Les chemins extra sont explicites. Le réseau est fermé par défaut.
- Fichiers de secrets : mettre
.enven deny. Ne pas s’en remettre à une phrase « ne lisez pas les secrets ».
Les outils MCP sont une autre table. Chaque outil a encore besoin d’une porte. Contraste de protocole : MCP Tool Schema vs Function Calling. Ce texte ne décrit pas comment les agents de code appellent MCP. Il exige seulement qu’un outil connecté ait un nom dans l’objet de permissions.
Cinq pas vers une politique exécutable
Ne pas partir de « veuillez exécuter avec prudence ». Écrire les portes :
- Écrire deny d’abord. Push, hooks, config, .env et chemins hors espace, une fois.
- Mettre les commandes en lecture sur allow. status, diff, test. Une règle par sous-commande pour les composées.
- Mettre écritures et commits sur ask. Une personne voit le chemin et le diff. Une approbation d’édition meurt avec la session.
- Activer le bac à sable OS. Codex :
:workspace, pas un:danger-full-accessde circonstance. Cursor : ne pas défautter sur Run Everything. LebypassPermissionsde Claude reste dans un conteneur isolé. - Relire la politique comme JSON. Étaler allow à côté de deny. Les règles partagées vont en contrôle de version. L’élargissement local reste local.
Comment Schema devient une porte : API Agents + JSON Schema. Ce texte demande seulement que chaque porte d’un agent de code soit un objet évalué par l’hôte.
Relire un écart de permissions en étalant deux traces JSON
Une porte franchie est souvent une règle mal alignée, pas un modèle plus sauvage.
- formater la politique à côté de ce
tool_use. Voir si deny a matché ou si allow a fuité. - Avec extraire en JSONPath, extraire
$.permissions.denyet$.input.command. - JSON Diff un passage et un refus. Corriger la règle avant le prompt.
- Relire les règles de métadonnées Git à part des écritures src. Modifier
A-1042.jsonn’est pas modifier hooks. - Ne pas coller politiques, chemins de dépôt ou journaux de session dans un formateur public. JSONSort tourne dans le navigateur, en local.
Si les deux traces se reconstruisent contre les règles, vous avez collecté un modèle de permissions. Sinon vous avez collecté « j’ai cliqué Autoriser ».
Pièges courants
- Prendre Schema pour une permission. Schema verrouille la forme. Un
git pushbien formé a encore besoin de deny. - N’écrire que allow. L’ordre officiel évalue deny d’abord. Sans deny, la liste ne fait qu’accélérer les approbations.
- Prendre l’écriture workspace pour une écriture Git. hooks et config sont une autre porte. Les défauts officiels les protègent.
- Deny d’outil sans bac à sable. Un script qui ouvre des fichiers lui-même est hors des règles d’outil. Il faut une frontière de processus.
- bypass / full-access / Run Everything sur un portable. La doc officielle les réserve aux environnements isolés. Les sessions du jour : workspace + ask.
- Mélanger l’ancien et le nouveau Codex. Si
sandbox_modeest présent, les profils ne s’appliquent pas. En choisir un.
FAQ
« Autoriser et ne plus demander » veut-il dire un octroi permanent ?
Pas toujours. Chez Claude Code, une approbation Bash durable tombe dans settings.local.json à la racine du dépôt ; une approbation d’édition meurt avec la session. La liste Cursor vit dans permissions.json. Lire l’objet écrit. Ne pas croire le libellé du bouton.
Si le bac à sable est actif, faut-il encore deny ?
Oui. Le bac à sable empêche un processus de quitter l’espace de travail. deny empêche des commandes qui ne doivent pas y tourner, comme push. Les deux couches verrouillent des portes différentes.
Pourquoi Git est-il une porte à part ?
Les métadonnées du dépôt ne sont pas un fichier ordinaire. Pouvoir éditer src n’est pas pouvoir éditer hooks et config. push est sortant, pas une écriture disque. Les produits officiels les sortent de « workspace inscriptible ».
Le mode lecture seule suffit-il ?
Pour lire du code. Pas pour changer A-1042. Codex :read-only, Claude plan et le bac à sable lecture de Cursor sont des profils d’exploration, pas de publication.
La politique peut-elle vivre dans Git ?
Oui, et elle le devrait. Le deny / allow partagé va en contrôle de version. L’élargissement local reste local et n’est pas commité. Les réglages gérés coupent bypass et auto.
Conclusion
Les agents de code ont besoin d’un contrôle de permissions parce que le modèle ne remplit que du JSON. Shell, Git et le système de fichiers sont trois portes. Après Schema, l’hôte évalue encore.
Écrivez quel deny git push rencontrerait. Si vous pouvez pointer un chemin, la politique est vérifiable. Les modèles changent. Les portes doivent d’abord tenir.
Pour aller plus loin
- Comment les agents de code IA appellent les outils en JSON JSON d’outil dans Claude Code et les agents GPT
- Crise de sécurité des agents et validation JSON Collecter la surface d’attaque, pas l’objet de permissions
- L’incident de sécurité Claude et le JSON d’outil Comment les arguments ont dérivé dans un incident
- API Agents + JSON Schema en pratique Trois portes : stable, vérifiable, exécutable
- Pourquoi l’IA a besoin de JSON Schema Schema / Function Calling / Structured Output
- Boîte à outils locale JSONSort Formater, valider, Diff
- Tous les articles Plus de notes JSON et IA
Journal : Première publication