Action is proposed as structured data (tool + args).
Le problème (côté prod)
Un agent, c’est “juste du texte”. Jusqu’au moment où tu lui donnes des tools.
Dès qu’il peut appeler des tools, tu as construit un système de permissions. Que tu le veuilles ou non.
Et la vérité qui pique : les prompts ne sont pas des permissions. “Please don’t do X” n’est pas un control layer.
Pourquoi ça casse en prod
1) “On donne l’accès, on contraindra après” finit en incident
Si tu dis “on ajoutera des guardrails après avoir prouvé la valeur” : tu décris la scène d’ouverture du postmortem.
2) Les tools sont des capacités, pas des fonctions
db.write n’est pas “une fonction”.
C’est une capacité : elle change l’état.
Les side effects sont irréversibles ou coûteux.
Conçois les permissions comme un graphe de capacités :
- read vs write
- ressources scoppées (tenant/projet/utilisateur)
- limites (rate/cost/steps)
3) Default-allow → fuites et cross-tenant tôt ou tard
Default-allow + un tool call faux et tu as :
- PII dans les logs
- writes dans le mauvais env
- accès cross-tenant
Exemple d’implémentation (code réel)
Un modèle minimal :
- allowlist capability-based
- checks de scope (tenant_id)
- write tools optionnels derrière approval
from dataclasses import dataclass
@dataclass(frozen=True)
class ToolPermission:
name: str
scopes: set[str] # e.g. {"tenant:acme"}
mode: str = "allow" # allow | approve
class PolicyDenied(RuntimeError):
pass
def check_permission(perms: list[ToolPermission], *, tool: str, scope: str) -> ToolPermission:
for p in perms:
if p.name == tool and scope in p.scopes:
return p
raise PolicyDenied(f"policy_denied:{tool}:{scope}")export class PolicyDenied extends Error {}
export function checkPermission(perms, { tool, scope }) {
for (const p of perms) {
if (p.name === tool && p.scopes.includes(scope)) return p;
}
throw new PolicyDenied("policy_denied:" + tool + ":" + scope);
}Incident réel (avec chiffres)
Un agent avait accès à un wrapper DB “admin” parce que c’était “plus simple”. Il devait trier des tickets support.
Une prompt injection dans un ticket l’a poussé à exécuter une requête qui retournait plus de données que nécessaire.
Impact :
- pas de fuite externe (heureusement)
- mais PII dans les logs internes (ça compte quand même)
- ~6 heures d’incident + cleanup + audit
Fix :
- least privilege par tool (scoped creds)
- redaction des outputs dans le tool gateway
- allowlist + approvals pour les writes
Compromis
- Un modèle de permissions coûte du dev time. C’est moins cher que l’incident time.
- Plus de scopes = plus de gestion de policy.
- Trop restrictif peut freiner le produit → il faut de bons defaults et une escalade claire.
Quand NE PAS l’utiliser
- Même avec des tools read-only, tu veux des scopes (boundaries tenant).
- Si un tool ne peut pas être scoppé (il peut “tout faire”), corrige le tool, pas la policy.
Checklist (copier-coller)
- [ ] Noms d’outils capability-based (read vs write)
- [ ] Default-deny allowlist
- [ ] Credentials scoppés (tenant/user/project)
- [ ] Mode approval pour writes irréversibles
- [ ] Redaction outputs (PII) + logging
- [ ] Stop reasons : policy_denied
Config par défaut sûre (JSON/YAML)
tool_permissions:
default: "deny"
grants:
- tool: "kb.read"
scopes: ["tenant:acme"]
mode: "allow"
- tool: "ticket.close"
scopes: ["tenant:acme"]
mode: "approve"
logging:
redact_outputs: true
FAQ (3–5)
Utilisé par les patterns
Pannes associées
Gouvernance requise
Q: Pourquoi un prompt ne suffit pas comme permission ?
A: Parce qu’un prompt n’enforce rien. Le modèle peut se tromper, halluciner ou être injecté.
Q: J’ai vraiment besoin de scopes ?
A: Oui, dès que tu es multi-tenant ou que tu as plusieurs envs. Sinon tu vas leak tôt ou tard.
Q: Comment combiner permissions et budgets ?
A: Permissions = “a-t-il le droit ?”. Budgets = “combien de temps / combien ça coûte ?”. Tu veux les deux.
Q: Où enforce tout ça ?
A: Dans le tool gateway. Pas dans l’UI, pas dans le prompt.
Pages liées (3–6 liens)
- Foundations: How agents use tools · Stateless vs stateful agents
- Failure: Prompt injection attacks · Tool response corruption
- Governance: Allowlist vs blocklist · Human approvals
- Production stack: Production agent stack