Action is proposed as structured data (tool + args).
El problema (en producción)
El agente es “solo texto”. Hasta que le das tools.
En cuanto puede llamar tools, construiste un sistema de permisos. Lo quieras o no.
Y la verdad incómoda: los prompts no son permisos. “please don’t do X” no es un control layer.
Por qué esto se rompe en producción
1) “Dale acceso y lo limitamos después” termina en incidente
Si dices “ponemos guardrails después de validar valor”: estás describiendo la escena inicial del postmortem.
2) Los tools son capacidades, no funciones
db.write no es “una función”.
Es una capacidad: cambia estado.
Los side effects son caros o irreversibles.
Diseña permisos como grafo de capacidades:
- read vs write
- scopes por recurso (tenant/proyecto/usuario)
- límites (rate/costo/steps)
3) Default-allow es cómo terminas con leaks
Default-allow + un tool call malo y tienes:
- PII en logs
- writes en el ambiente equivocado
- acceso cross-tenant
Ejemplo de implementación (código real)
Modelo mínimo:
- allowlist basada en capacidades
- checks de scope (tenant_id)
- write tools opcionalmente detrás de 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);
}Incidente real (con números)
Un agente tenía acceso a un wrapper DB “admin” porque era “más fácil”. Se suponía que triageaba tickets de soporte.
Una prompt injection en un ticket lo empujó a ejecutar una query que devolvía más datos de los necesarios.
Impacto:
- sin exfiltración externa (por suerte)
- pero PII en logs internos (igual cuenta)
- ~6 horas de incidente + limpieza + auditoría
Fix:
- least privilege por tool (credenciales con scope)
- redacción de outputs en el tool gateway
- allowlist + approvals para writes
Trade-offs
- Un modelo de permisos cuesta tiempo de ingeniería. Es más barato que tiempo de incidentes.
- Más scopes = más management de policy.
- Muy restrictivo puede frenar producto → necesitas defaults buenos + escalación clara.
Cuándo NO usarlo
- Incluso con tools read-only, quieres scopes (límites de tenant).
- Si no puedes scoping en un tool (puede “hacer todo”), arregla el tool primero.
Checklist (copiar/pegar)
- [ ] Nombres de tools por capacidad (read vs write)
- [ ] Default-deny allowlist
- [ ] Credenciales con scope por tenant/user/proyecto
- [ ] Modo approval para writes irreversibles
- [ ] Redacción de outputs (PII) + logging
- [ ] Stop reasons: policy_denied
Config segura por defecto (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)
Usado por patrones
Fallos relacionados
- AI Agent Infinite Loop (Detectar + arreglar, con código)
- Explosión de presupuesto (cuando un agente quema dinero) + fixes + código
- Tool Spam Loops (fallo del agente + fixes + código)
- Incidentes de exceso de tokens (prompt bloat) + fixes + código
- Corrupción de respuestas de tools (schema drift + truncation) + código
P: ¿Por qué un prompt no alcanza como permiso?
R: Porque un prompt no enforcea. El modelo puede fallar, alucinar o ser inyectado.
P: ¿Necesito scopes de verdad?
R: Sí, si eres multi-tenant o tienes varios entornos. Si no, vas a filtrar tarde o temprano.
P: ¿Cómo combino permisos y budgets?
R: Permisos = “puede hacerlo”. Budgets = “cuánto tiempo/cuánto cuesta”. Necesitas ambos.
P: ¿Dónde enforceo esto?
R: En el tool gateway. No en la UI, no en el prompt.
Páginas relacionadas (3–6 links)
- 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