What Permissions Should I Give My AI Agent? The Principle of Least Privilege
I gave my AI agent read access to ~/.ssh because I thought it might need to deploy code someday.
Three weeks later, a malicious skill I installed from a public repository exfiltrated my private keys.
The agent wasn’t hacked. It did exactly what I told it to do—access files in ~/.ssh. The skill was designed to steal keys. My permission decision created the vulnerability.
The Problem with “Might Be Useful” Permissions
When setting up AI agents, developers often think:
- “Maybe it’ll need to read config files from
~/.aws?” - “What if I want it to access my environment variables?”
- “Let’s give it full filesystem read access just in case.”
This thinking is backwards.
An agent with access to only two specific folders and one API cannot leak your entire filesystem through a malicious skill. An agent with no write permissions on critical paths cannot be used to modify production data through a prompt injection.
The attack surface of an AI agent isn’t a bug in the code. It’s the designed behavior when pointed at inputs the designer didn’t anticipate.
What Least Privilege Actually Means for AI Agents
Traditional least privilege: “Give users minimum permissions to do their job.”
AI agent least privilege: “Give the agent access only to resources it needs for its defined tasks—not what might be useful someday.”
Here’s the key difference:
Traditional App: Attackers exploit bugs in code → Fix the bug, problem solved
AI Agent: Attackers exploit designed capabilities → Can't "fix" capabilities without breaking functionality → Must LIMIT capabilities insteadA database query endpoint is designed to accept queries. An AI agent is designed to execute with its granted permissions. Neither is a bug. Both become vulnerabilities when an attacker finds unexpected ways to use them.
Real-World Permission Scoping
Let me show you three concrete scenarios:
Scenario 1: Code Assistant Agent
✅ NEEDS: - Read/Write: ~/projects/myapp/src - Network: api.openai.com, github.com
❌ DOES NOT NEED: - Read: ~/.ssh, ~/.aws, ~/.env - Write: /etc, ~/.config, ~/.ssh - Network: *.internal.company.comIf a malicious skill tries to read ~/.ssh/id_rsa, the agent simply cannot access it. No amount of prompt injection or social engineering changes that.
Scenario 2: Documentation Generator
✅ NEEDS: - Read: ~/docs/source - Write: ~/docs/output
❌ DOES NOT NEED: - Any network access - Any execution permissions (shell commands) - Read access outside ~/docs/sourceThis agent cannot exfiltrate data. It cannot modify source code. It cannot reach external servers. It can only read documentation and write documentation.
Scenario 3: Data Pipeline Agent
✅ NEEDS: - Read: ~/data/input - Write: ~/data/output - Network: internal-api.company.com:443
❌ DOES NOT NEED: - Read: ~/personal, ~/.credentials - Write: ~/personal, /etc - Network: External services, cloud providersEven if an attacker compromises the internal API response to inject malicious instructions, the agent has nowhere to send exfiltrated data and no access to sensitive personal files.
How to Implement Least Privilege
Start with nothing, add only what’s needed:
agent: name: "docs-generator"
# Start with DENY ALL permissions: filesystem: read: [] # Add only specific paths write: [] # Add only specific paths network: allow: [] # Add only specific domains execution: allowed: false # Default to no shell access
# Then explicitly grant minimum needed permissions: filesystem: read: - ~/projects/myapp/docs write: - ~/projects/myapp/docs/output network: allow: [] # No network needed for this agent execution: allowed: falseThe configuration above is explicit. No guessing. No “let me check what it has access to.”
The Blast Radius Test
Ask yourself: “If this agent gets compromised, what’s the maximum damage?”
| Permission Level | Blast Radius |
|---|---|
| Full filesystem read | All your files, credentials, secrets |
| Full filesystem write | Ransomware, data destruction, backdoors |
| Full network access | Data exfiltration to any server |
| Scoped to task | Limited to specific folders/APIs |
A compromised agent with least privilege applied can only affect the specific resources it was designed to touch. That’s the entire point.
Common Permission Mistakes
Mistake 1: Inheriting User Permissions
Don’t run agents with your user permissions. Create isolated permission profiles.
# WRONG: Agent inherits your permissions./agent run # Uses your ~/.aws, ~/.ssh, etc.
# RIGHT: Agent has its own scoped permissions./agent run --config agent-permissions.yamlMistake 2: Granting “Read-Only” Without Scope
Read access to ~ is not “safe.” It includes:
~/.ssh/- Your private keys~/.aws/credentials- Your AWS credentials~/.envfiles - Your environment variables~/.config/- Your application configs
Mistake 3: Assuming Skills Are Trustworthy
You might trust the agent framework, but what about:
- Third-party skills from public repositories
- Skills that auto-update
- Skills with transitive dependencies
A skill runs with the agent’s permissions. If the agent can read ~/.ssh, any skill can read ~/.ssh.
Implementing with OpenClaw
OpenClaw provides permission boundaries at the agent level:
from openclaw import Agent, Permissions
# Define strict permissionsperms = Permissions( read_paths=["~/projects/myapp/src"], write_paths=["~/projects/myapp/src"], allowed_domains=["api.openai.com", "github.com"], allow_execution=False)
agent = Agent( name="code-assistant", permissions=perms)
# If compromised, only ~/projects/myapp/src is affectedThe permission boundary is enforced at the framework level. Even if a skill or prompt tries to access ~/.aws, the request is denied—not by the skill, not by the model, but by the permission boundary.
When You Need More Permissions
Sometimes your agent genuinely needs broader access:
- DevOps agent needs cloud provider credentials
- Data agent needs database connection strings
- Deployment agent needs SSH keys
Solution: Create separate agents with isolated permissions.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│ Code Agent │ │ Deploy Agent │ │ Data Agent ││ │ │ │ │ ││ Read: src/ │ │ Read: ~/.ssh │ │ Read: ~/data ││ Write: src/ │ │ Write: none │ │ Write: output/ ││ Network: github│ │ Network: prod │ │ Network: db │└─────────────────┘ └─────────────────┘ └─────────────────┘ ↓ ↓ ↓ Limited Isolated Scoped to code to deployment to dataEach agent has its own permission boundary. Compromising one doesn’t compromise all.
Key Takeaways
- Start with nothing - Grant permissions incrementally, not by default
- Scope to the task - If the agent is for docs, it doesn’t need code write access
- Network is access - Allowed domains are potential data exfiltration channels
- Skills inherit permissions - Any installed skill runs with full agent permissions
- Test the blast radius - Ask “what’s the worst that can happen?” and reduce accordingly
The principle isn’t about preventing all attacks. It’s about ensuring that when something goes wrong—malicious skill, prompt injection, compromised model—the damage is contained.
Least privilege doesn’t make your agent unhackable. It makes the hack smaller.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments