Tool Permissions for AI Agents
What this article covers
- How to configure tool permissions for AI agents
- How to implement least privilege, roles, and approvals
- How to restrict, monitor, and audit tool access
- Practical examples for filesystem, network, and shell tools
- Best practices for security, hierarchy, and human-in-the-loop
Introduction: Understanding tool permissions for AI agents
AI agents call tools to accomplish tasks: reading files, sending emails, executing shell commands. Each tool is a capability the agent can use. Give an agent too many tools and it can do too much. Give it too few and it cannot complete its mission. Tool permissions constrain agent access to only those tools it actually needs.
This article is for developers building and securing AI agents. You should be familiar with AI agents and how function calling works. Python fundamentals are available on IRC-Coding.de.
Why do you need tool permissions?
Imagine building an agent to answer emails. You give it tools for email sending, filesystem access, and shell execution. The agent should only reply to emails, yet now it can delete files or run arbitrary shell commands. If the agent is compromised via prompt injection, it could perform destructive actions.
Tool permissions solve this: the agent gets only the tools needed for its task. An email agent gets email tools, not shell access. A file agent gets read permissions, not write permissions. This principle is called least privilege.
Tool permissions explained
Tool permissions control what tools an agent can access. The agent receives only those tools it needs for its assigned task, with the minimum rights necessary. This follows the principle of least privilege: as many permissions as required, as few as possible.
The core idea: an agent whose job is to answer emails needs no shell access.
Who should read this
- Developers building and securing AI agents
- Security teams defining agent permissions
- System administrators running agents in production
- Organizations deploying agents safely
Prerequisites include experience with Python, AI agents, and function calling.
Key concepts
- Tool permission - right to use a specific tool. Use when: establishing baseline access control
- Least privilege - principle of minimal permissions. Use when: implementing security standards
- Role - collection of permissions. Use when: managing access across multiple agents
- Approval - human confirmation for a tool call. Use when: guarding critical actions
- Audit - logging all tool invocations. Use when: demonstrating accountability
- AI agents - programs that invoke tools. Use when: determining what needs protection
- Function calling - structured AI responses. Use when: understanding how tools are invoked
- Human approval - human-in-the-loop verification. Use when: controlling sensitive operations
- Sandbox environments - isolated execution. Use when: running untrusted code
- Prompt injection protection - defense against manipulation. Use when: permissions alone are insufficient
Permission levels
Tools can be offered at different levels:
| Level | Description | Example |
|---|---|---|
| Full access | Agent can use tool without approval | read_file for logs |
| Approval required | Agent can use tool, but human must confirm | send_email |
| Restricted | Agent can use tool with parameter limits | read_file only in /data/ |
| Disabled | Tool is unavailable | execute_shell for email agent |
Implementing a permission system
Tool definition with permissions
from enum import Enum
class Permission(Enum):
ALLOWED = "allowed"
REQUIRES_APPROVAL = "requires_approval"
RESTRICTED = "restricted"
DISABLED = "disabled"
class Tool:
def __init__(self, name, description, permission, parameters=None, restrictions=None):
self.name = name
self.description = description
self.permission = permission
self.parameters = parameters or {}
self.restrictions = restrictions or {}
def can_execute(self, parameters=None):
if self.permission == Permission.DISABLED:
return False
if self.permission == Permission.RESTRICTED:
return self.check_restrictions(parameters)
return True
def check_restrictions(self, parameters):
for key, allowed_values in self.restrictions.items():
if key in parameters:
if parameters[key] not in allowed_values:
return False
return True
Defining roles
class Role:
def __init__(self, name, tools):
self.name = name
self.tools = {t.name: t for t in tools}
def get_tool(self, tool_name):
return self.tools.get(tool_name)
def can_use(self, tool_name):
return tool_name in self.tools and self.tools[tool_name].permission != Permission.DISABLED
# Define roles
email_agent_role = Role("email_agent", [
Tool("read_email", "Read email", Permission.ALLOWED),
Tool("send_email", "Send email", Permission.REQUIRES_APPROVAL),
Tool("classify_email", "Classify email", Permission.ALLOWED),
Tool("execute_shell", "Execute shell command", Permission.DISABLED),
])
file_agent_role = Role("file_agent", [
Tool("read_file", "Read file", Permission.RESTRICTED, restrictions={
"path": ["/data/", "/tmp/"]
}),
Tool("write_file", "Write file", Permission.REQUIRES_APPROVAL, restrictions={
"path": ["/data/"]
}),
Tool("delete_file", "Delete file", Permission.REQUIRES_APPROVAL),
Tool("execute_shell", "Execute shell command", Permission.DISABLED),
])
Agent with permissions
class SecureAgent:
def __init__(self, role, model="llama3.1"):
self.role = role
self.model = model
def call_tool(self, tool_name, parameters):
# Check permission
tool = self.role.get_tool(tool_name)
if not tool:
raise PermissionError(f"Tool {tool_name} not available in role {self.role.name}")
if not tool.can_execute(parameters):
raise PermissionError(f"Tool {tool_name} cannot execute with these parameters")
# Approval needed?
if tool.permission == Permission.REQUIRES_APPROVAL:
approved = request_human_approval(tool_name, parameters)
if not approved:
return {"status": "denied", "reason": "Human approval denied"}
# Execute tool
result = execute_tool(tool_name, parameters)
# Audit log
audit_log(tool_name, parameters, result)
return result
Practical Example 1: Email Agent with Permissions
# Define role
email_role = Role("email_agent", [
Tool("read_email", "Read email", Permission.ALLOWED),
Tool("send_email", "Send email", Permission.REQUIRES_APPROVAL),
Tool("delete_email", "Delete email", Permission.REQUIRES_APPROVAL),
Tool("execute_shell", "Shell", Permission.DISABLED),
Tool("read_file", "Read file", Permission.RESTRICTED, restrictions={
"path": ["/data/templates/"]
}),
])
# Create agent
agent = SecureAgent(email_role)
# Allowed: read email
agent.call_tool("read_email", {"id": 123})
# Allowed with approval: send email
agent.call_tool("send_email", {"to": "user@example.com", "subject": "Test"})
# Forbidden: execute shell
try:
agent.call_tool("execute_shell", {"command": "rm -rf /"})
except PermissionError:
print("Shell execution forbidden")
Practical Example 2: File Agent with Path Restrictions
file_role = Role("file_agent", [
Tool("read_file", "Read file", Permission.RESTRICTED, restrictions={
"path": ["/data/", "/tmp/"]
}),
Tool("write_file", "Write file", Permission.RESTRICTED, restrictions={
"path": ["/data/"]
}),
])
agent = SecureAgent(file_role)
# Allowed: read file in /data/
agent.call_tool("read_file", {"path": "/data/document.txt"})
# Forbidden: read file in /etc/
try:
agent.call_tool("read_file", {"path": "/etc/passwd"})
except PermissionError:
print("Access to /etc/ forbidden")
Practical Example 3: Code Agent with Sandbox
code_role = Role("code_agent", [
Tool("write_code", "Write code", Permission.ALLOWED, restrictions={
"language": ["python", "javascript"]
}),
Tool("run_code", "Run code", Permission.REQUIRES_APPROVAL, restrictions={
"sandbox": ["docker", "firejail"]
}),
Tool("read_file", "Read file", Permission.RESTRICTED, restrictions={
"path": ["/workspace/"]
}),
Tool("write_file", "Write file", Permission.RESTRICTED, restrictions={
"path": ["/workspace/"]
}),
])
# Code execution only in sandbox
agent = SecureAgent(code_role)
agent.call_tool("run_code", {
"code": "print('Hello')",
"sandbox": "docker"
})
See Sandbox Environments for details.
Human-in-the-Loop for Critical Actions
def request_human_approval(tool_name, parameters):
print(f"\n--- Approval Required ---")
print(f"Tool: {tool_name}")
print(f"Parameters: {parameters}")
print(f"Approve? (y/n): ")
response = input().strip().lower()
return response == "y"
# In practice: web UI, Slack bot, email confirmation
See Human Approval for details.
Audit Logging for Tool Calls
import json
from datetime import datetime
def audit_log(tool_name, parameters, result, agent_id="default"):
entry = {
"timestamp": datetime.now().isoformat(),
"agent_id": agent_id,
"tool": tool_name,
"parameters": parameters,
"result_status": result.get("status", "unknown"),
"approved": True
}
with open("/var/log/agent_audit.log", "a") as f:
f.write(json.dumps(entry) + "\n")
See Logging for details.
Security Best Practices
- Least Privilege: Give the agent only the tools it needs. No shell access for email agents.
- Approval for Critical Actions: Deletion, sending, and execution should require approval.
- Audit Logging: Log all tool calls with parameters and results.
- Prompt Injection Protection: Permissions alone are not enough. Protect against manipulation. See Prompt Injection Protection.
- Sandbox for Code Execution: Code agents must run in a sandbox. See Sandbox Environments.
- Parameter Validation: Check tool parameters, not just tool names. Path restrictions, command whitelists.
- Regular Review: Check permissions regularly. Does the agent still need all its tools?
Common Pitfalls
- Too Many Tools: The agent gets all tools because it’s easier. Security risk.
- No Approval for Critical Actions: Deletion without approval is dangerous.
- No Parameter Validation: Tool is allowed, but parameters are not checked. Path traversal becomes possible.
- No Audit Logging: Without logs, there’s no accountability.
- Permissions Never Reviewed: The agent no longer needs a tool, but keeps it anyway.
- Prompt Injection Overlooked: The agent gets manipulated, permissions bypassed.
Further Reading and Resources on Tool Permissions
- AI Agents Fundamentals - What AI agents are.
- Function Calling - How tools are invoked.
- Human Approval - Human-in-the-loop.
- Sandbox Environments - Isolated execution.
- Prompt Injection Protection - Protection against manipulation.
- Configuring Guardrails - Guardrails.
- Logging - Audit logging.
- Least Privilege - Principle of minimal rights.
Key Takeaways:
- Tool permissions restrict an agent’s access to tools.
- Least Privilege: as much access as necessary, as little as possible.
- Require approval for critical actions: deletion, sending, execution.
- Validate parameters: check not just tool names, but also parameters.
- Audit log all tool calls.
FAQ: Tool Permissions for AI Agents - Common Questions
What are tool permissions?
What is Least Privilege?
When do I need human-in-the-loop?
Why parameter validation?
How do I define roles?
Why audit logging?
Do permissions protect against prompt injection?
When do I need a sandbox?
How often should I review permissions?
How many tools should an agent have?
References and Further Reading
- OWASP LLM Top 10 - Security risks in LLMs.
- NIST AI Risk Management Framework - AI risk management.
- MCP Security - Model Context Protocol.
- Ollama - Local model server.


