Tool Allowlist
An agent is not ready for production until it operates under default-deny tool access: no tool is callable unless explicitly added to an allowlist for the current task. If the agent calls a tool that is not on the contract, stop and treat it as a policy violation.
This is the privilege boundary. Without it, one prompt injection can escalate to arbitrary tool execution.
When to run
- Designing a new agent or multi-agent system
- Setting up production agent deployment
- Investigating "how did the agent execute that dangerous command"
- Implementing tool governance or audit requirements
If you cannot name the allowlist for this agent's current task, the agent is running with no policy.
The allowlist model
A tool allowlist is the explicit set of tools an agent may call for the current task. Everything else is denied.
Core principles
- Default-deny — if a tool is not explicitly allowed, it is denied
- Deny wins — explicit denies always override allows
- Per-task scoping — allowlists are narrow and change per task, not global
- Runtime enforcement — the policy layer evaluates every tool call before execution
Sources:
What it is NOT
- Not a blocklist — blocklists only forbid known-bad tools; they permit everything new by default (insecure)
- Not client-side suggestions — client-side permissions can be bypassed by a compromised agent
- Not static — the allowlist should change per task; a file-read task gets fewer tools than a deployment task
How to implement
1. Deploy a policy gateway
The allowlist must be enforced outside the agent process. A policy gateway sits between the agent and its tools, intercepts every tool call, and decides: allow, deny, or approval-required.
┌─────────────┐
│ Agent │
└──────┬──────┘
│ tool call
▼
┌─────────────────────┐
│ Policy Gateway │ ← enforces default-deny
│ (allow/deny/audit) │
└──────┬──────────────┘
│ allowed
▼
┌─────────────┐
│ Tool │
└─────────────┘
Tools:
- SecAI-Hub/agent-tool-firewall — lightweight HTTP policy gateway
- Spin42/denyx — MCP policy layer with default-deny
Sources:
2. Define the policy file
Policies are written in YAML and declare which tools are allowed, denied, and require approval:
# policy.yaml
default: "deny" # CRITICAL: default-deny mode
rate_limit:
requests_per_minute: 120
allow:
- name: "filesystem.read"
paths_allowlist:
- "$HOME/documents/**"
paths_denylist:
- "/etc/shadow"
max_arg_length: 4096
- name: "web.search"
args_blocklist:
- "password"
- "secret"
deny:
- name: "shell.exec" # explicit deny always wins
requires_approval:
- name: "filesystem.write"
- name: "api.delete"
Key decisions:
default: "deny"— this line is non-negotiable; without it, new tools are auto-alloweddenybeatsallow— if a tool appears in both, deny winspaths_allowlist— narrow filesystem access to specific directoriesrequires_approval— human-in-the-loop for irreversible actions
Sources:
3. Enforce at runtime
On every tool call:
- Rate limit — reject if over budget
- Explicit deny — if tool is on the deny list, block immediately
- Allowlist check — if tool is not on the allow list, block (default-deny)
- Argument validation — check length limits, blocked patterns, path traversal
- Log decision — record allow/deny/approval with tool name, arguments, agent identity
{
"timestamp": "2026-08-16T03:00:00Z",
"agent_id": "agent-42",
"tool": "filesystem.read",
"args": { "path": "$HOME/documents/report.pdf" },
"decision": "allow",
"policy_rule": "filesystem.read allow rule #1"
}
Sources:
4. Filter tool discovery
The gateway should strip denied tools from the agent's view so the model cannot even see or attempt to call them.
If the agent has 76 tools registered but only 12 are allowed for the current task, the agent sees only those 12.
Sources:
Stop conditions — when NOT to proceed
STOP if any of the following is true:
- The agent has access to tools but no policy file exists
- The policy file has
default: "allow"or nodefaultkey (not default-deny) - The policy is enforced client-side only (can be bypassed)
- The agent called a tool that is not on the allowlist and was not blocked
- No audit log exists for tool-call decisions
Do not deploy. Build the policy layer first.
Per-task scoping
Allowlists should be narrow and task-specific, not static.
Example: code-review agent
allow:
- name: "git.diff"
- name: "git.show"
- name: "github.comment"
deny:
- name: "git.push" # read-only for review tasks
- name: "filesystem.write"
Example: deployment agent
allow:
- name: "git.push"
- name: "vercel.deploy"
- name: "github.status"
requires_approval:
- name: "vercel.deploy" # deployment requires human gate
The allowlist changes per agent role, not per agent instance.
Sources:
Verification checklist
Before deploying an agent:
- ☐ A policy file exists with
default: "deny" - ☐ The policy is enforced by a gateway outside the agent process
- ☐ The allowlist is scoped to the agent's task (not "allow everything")
- ☐ Denied tools are stripped from the agent's tool discovery
- ☐ Human-approval gates are defined for irreversible actions
- ☐ Every tool call is logged with the policy decision
- ☐ Audit logs are monitored for deny spikes (signals policy drift)
If any checkbox is unchecked, the agent is running with no privilege boundary. Build the gate, then deploy.
Common mistakes
- Relying on blocklists — blocklists only stop known-bad tools; new tools are auto-allowed
- Client-side enforcement only — a compromised agent bypasses client-side checks
- One global allowlist — every agent gets every tool; no task scoping
- No audit log — you cannot investigate "how did it call that" without logs
Sources:
Without default-deny, one prompt injection can call any tool in your estate. Allowlists are not nice-to-have; they are the privilege boundary.