Allowlist vs Blocklist (Pourquoi le default-deny gagne) + Code

Les blocklists pourrissent. Les allowlists scalent. Un modèle de policy outils qui n’autorise pas par accident le prochain outil dangereux.
Sur cette page
  1. Le problème (côté prod)
  2. Pourquoi ça casse en prod
  3. 1) Tu ne peux pas lister « tous les outils dangereux » à l’avance
  4. 2) Les blocklists cassent sur le naming et l’indirection
  5. 3) Le default-allow fait grossir la blast radius en silence
  6. 4) Les allowlists forcent une décision explicite
  7. Exemple d’implémentation (code réel)
  8. Incident réel (avec chiffres)
  9. Compromis
  10. Quand NE PAS l’utiliser
  11. Checklist (copier-coller)
  12. Config par défaut sûre (JSON/YAML)
  13. FAQ (3–5)
  14. Pages liées (3–6 liens)
Flux interactif
Scénario:
Étape 1/3: Execution

Action is proposed as structured data (tool + args).

Le problème (côté prod)

Tu commences par une blocklist parce que c’est rapide : « on interdit les trucs dangereux ».

Puis tu ajoutes un nouvel outil. Personne ne pense à mettre à jour la blocklist. L’agent le découvre.

Et maintenant tu es d’astreinte parce que « interdire les trucs dangereux » était surtout une histoire que tu te racontais.

Les blocklists donnent l’impression de contrôle. En systèmes d’agents, c’est souvent un piège. Et ça pourrit vite : deux semaines après, plus personne ne sait ce que la liste est censée protéger.

Pourquoi ça casse en prod

1) Tu ne peux pas lister « tous les outils dangereux » à l’avance

Aujourd’hui c’est db.delete_user. Demain c’est crm.merge_accounts. La semaine prochaine c’est tickets.close_all.

L’outil que tu as oublié de bloquer est celui qui te mord.

2) Les blocklists cassent sur le naming et l’indirection

Tu bloques db.write, quelqu’un ship db.patch. Tu bloques email.send, quelqu’un ship email.send_bulk.

Pire : les wrappers. L’agent appelle workflow.run("close_ticket") et ta « blocklist » ne voit jamais le vrai side effect.

3) Le default-allow fait grossir la blast radius en silence

Si ta policy dit « tout est autorisé sauf… », tu expédies une expansion de permissions par défaut. Chaque nouvel outil devient un incident en attente.

4) Les allowlists forcent une décision explicite

Les allowlists sont pénibles. Tant mieux. Elles t’obligent à dire : « oui, l’agent peut appeler cet outil, dans ces conditions ».

Exemple d’implémentation (code réel)

Un petit évaluateur de policy :

  • default-deny
  • deny list optionnelle pour l’Incident Mode (frein d’urgence)
  • « write tools → approbation »
PYTHON
from dataclasses import dataclass


WRITE_TOOLS = {"email.send", "db.write", "ticket.close"}


@dataclass(frozen=True)
class Policy:
  allow: set[str]
  deny: set[str] = None  # for incident mode
  require_approval_for_writes: bool = True


class Denied(RuntimeError):
  pass


def evaluate(policy: Policy, tool: str) -> str:
  deny = policy.deny or set()
  if tool in deny:
      raise Denied(f"denied: {tool} (incident mode)")
  if tool not in policy.allow:
      raise Denied(f"not allowed: {tool}")
  if policy.require_approval_for_writes and tool in WRITE_TOOLS:
      return "approve"
  return "allow"
JAVASCRIPT
const WRITE_TOOLS = new Set(["email.send", "db.write", "ticket.close"]);

export class Denied extends Error {}

export function evaluate(policy, tool) {
const deny = new Set(policy.deny || []);
if (deny.has(tool)) throw new Denied("denied: " + tool + " (incident mode)");
if (!policy.allow.includes(tool)) throw new Denied("not allowed: " + tool);
if (policy.requireApprovalForWrites && WRITE_TOOLS.has(tool)) return "approve";
return "allow";
}

Incident réel (avec chiffres)

On a vu une équipe shipper un agent avec une policy : « on bloque les outils dangereux ».

Puis ils ont ajouté un outil : ticket.close_bulk. Il n’était pas dans la deny list. L’agent l’a utilisé parce que c’était le chemin le plus court vers « resolve ».

Impact :

  • ~200 tickets fermés à tort
  • ~5 heures ingénieur à rouvrir, expliquer, patcher
  • l’agent a été désactivé une semaine : plus personne ne lui faisait confiance

Fix :

  1. allowlist default-deny
  2. write tools derrière approvals
  3. deny list réservée à l’Incident Mode (temporaire)

Les blocklists, c’est bien comme frein. C’est mauvais comme volant.

Compromis

  • Les allowlists ralentissent le « just ship it ». En prod, c’est un feature.
  • Il te faut du tooling pour gérer l’allowlist (ne la hardcode pas à 12 endroits).
  • Les gens vont tenter de contourner via des wrappers. Ne les laisse pas.

Quand NE PAS l’utiliser

  • En proto local, tu peux être plus permissif — mais ne remonte pas ça en prod.
  • Même en read-only, une petite allowlist évite des surprises.
  • Si ton « tool » est un RPC générique qui peut tout faire, corrige le tool d’abord : découpe par capacité.

Checklist (copier-coller)

  • [ ] Allowlist default-deny (noms d’outils explicites)
  • [ ] Outils séparés par capacité (read vs write)
  • [ ] Approvals pour les writes irréversibles
  • [ ] Deny list uniquement en Incident Mode (temporaire)
  • [ ] Log des denies (c’est un signal)
  • [ ] Pas d’outils génériques « do anything »

Config par défaut sûre (JSON/YAML)

YAML
policy:
  default: "deny"
  allow: ["search.read", "kb.read", "http.get"]
  require_approval_for_writes: true
incident_mode:
  deny: ["browser.run"] # frein temporaire
logging:
  log_denies: true

FAQ (3–5)

Les blocklists servent à quelque chose ?
Oui : Incident Mode, désactivations temporaires. C’est un frein d’urgence, pas un modèle de permissions.
Je peux utiliser des wildcards dans l’allowlist ?
Avec prudence. Les wildcards glissent vite vers le default-allow. Si tu en as besoin, garde-les étroites et review régulièrement.
Et les tools type ‘workflow.run’ ?
Ils cachent les side effects. Préfère des tools explicites pour que la policy puisse raisonner.
C’est quoi la policy minimale safe ?
Default-deny allowlist + tools read-only. Ajoute les writes plus tard, derrière approvals.

Q: Les blocklists servent à quelque chose ?
A: Oui : Incident Mode, désactivations temporaires. C’est un frein d’urgence, pas un modèle de permissions.

Q: Je peux utiliser des wildcards dans l’allowlist ?
A: Avec prudence. Les wildcards glissent vite vers le default-allow. Si tu en as besoin, garde-les étroites et review régulièrement.

Q: Et les tools type ‘workflow.run’ ?
A: Ils cachent les side effects. Préfère des tools explicites pour que la policy puisse raisonner.

Q: C’est quoi la policy minimale safe ?
A: Default-deny allowlist + tools read-only. Ajoute les writes plus tard, derrière approvals.

Pages liées (3–6 liens)

Pas sur que ce soit votre cas ?

Concevez votre agent ->
⏱️ 5 min de lectureMis à jour Mars, 2026Difficulté: ★★★
Implémenter dans OnceOnly
Budgets + permissions you can enforce at the boundary.
Utiliser dans OnceOnly
# onceonly guardrails (concept)
version: 1
budgets:
  max_steps: 25
  max_tool_calls: 12
  max_seconds: 60
  max_usd: 1.00
policy:
  tool_allowlist:
    - search.read
    - http.get
writes:
  require_approval: true
  idempotency: true
controls:
  kill_switch: { enabled: true }
Intégré : contrôle en productionOnceOnly
Ajoutez des garde-fous aux agents tool-calling
Livrez ce pattern avec de la gouvernance :
  • Budgets (steps / plafonds de coût)
  • Permissions outils (allowlist / blocklist)
  • Kill switch & arrêt incident
  • Idempotence & déduplication
  • Audit logs & traçabilité
Mention intégrée : OnceOnly est une couche de contrôle pour des systèmes d’agents en prod.
Auteur

Cette documentation est organisée et maintenue par des ingénieurs qui déploient des agents IA en production.

Le contenu est assisté par l’IA, avec une responsabilité éditoriale humaine quant à l’exactitude, la clarté et la pertinence en production.

Les patterns et recommandations s’appuient sur des post-mortems, des modes de défaillance et des incidents opérationnels dans des systèmes déployés, notamment lors du développement et de l’exploitation d’une infrastructure de gouvernance pour les agents chez OnceOnly.