Skip to main content

Least Privilege Has an Agent Problem

·956 words·5 mins

Your company spent years building IAM policies. You scoped OAuth tokens to the minimum grants. You rotated secrets on a schedule. You fought for RBAC and won.

Then someone handed an AI agent a root API key and told it to go process claims.

We learned the least-privilege playbook for human access decades ago. Agents inherit far less of it once they start calling real systems. The typical pattern: stuff an API key into an environment variable, give the agent an HTTP client, and hope the system prompt says “please don’t do anything dangerous.” In a regulated environment (SOC 2, NYDFS Part 500), hope is not a control. An auditor will not accept “we told the model not to” as a mitigation.

The easy part is already solved
#

Model vendors are starting to add their own permission controls. OpenAI supports restricted API keys. Anthropic’s Agent SDK has permission primitives. That helps for calls back to the model provider.

The real enterprise problem starts when agents leave the model API and begin touching GitHub, Slack, Jira, Stripe, internal services, and MCP servers. Some of these have their own scoping mechanisms (GitHub’s fine-grained PATs are solid), but most don’t, and agents typically touch many systems at once. A GitHub token with repo scope can delete branches. A Stripe secret key can issue refunds. The credential doesn’t know it was handed to an agent instead of a human, and your compliance framework doesn’t distinguish between the two. Least privilege breaks down at the boundaries between these systems.

Airlock
#

Airlock is a reverse proxy sidecar that sits between your agent and external APIs. The agent makes requests to localhost. Airlock decides what gets through.

It enforces least privilege at the HTTP layer: firewall-style access rules with implicit deny, auth injection so the agent never sees real credentials, credential redaction from responses, and per-route rate limiting. The policy is a YAML file. Declarative, version-controlled, reviewable in a PR.

routes:
  - path_prefix: "/github"
    upstream: "https://api.github.com"
    strip_prefix: "/github"
    auth:
      type: static
      token: { from: vault, path: "secret/github", key: "pat" }  # also supports env vars, files, AWS Secrets Manager
      header: "Authorization"
      prefix: "Bearer "
    access_rules:
      - action: ALLOW
        method: GET
        path: /repos/*/issues
      - action: ALLOW
        method: POST
        path: /repos/*/issues
      # Everything else: implicit DENY

This agent can read and create issues. It cannot delete repos, merge PRs, or modify workflows, even though the underlying token could. The blast radius shrinks to the operations you explicitly permit through the proxy. The policy is auditable by someone who’s never seen your codebase.

MCP tool filtering
#

This is where it gets interesting. Model Context Protocol servers expose tools over JSON-RPC, and a single MCP server might offer 40 tools. Your agent needs 3. Without filtering, the agent can call any of them. A prompt injection can steer it toward the destructive ones.

Because Airlock operates at the HTTP layer, it filters remote MCP servers communicating over HTTP/SSE (not local stdio servers). It inspects JSON-RPC traffic and enforces tool-level policy. You specify allowed_tools or denied_tools with glob patterns. The agent’s tools/list response gets filtered before it arrives. The agent never even sees tools it can’t use.

mcp_rules:
  allowed_tools:
    - "read_*"
    - "list_*"
  denied_tools:
    - "*_delete"

MCP is an increasingly important interface for agent tooling. If you’re not filtering at the protocol level, you’re trusting the agent to self-govern which tools it calls. That’s prompt-based security, and in a regulated environment, prompt-based security is not a sufficient control.

SSE-aware redaction
#

Most LLM APIs and MCP servers stream responses as Server-Sent Events. A naive proxy either buffers the entire response (breaking the stream) or passes it through without inspection (leaking credentials the proxy just injected).

Airlock is SSE-aware. It redacts injected credentials from streaming responses by scanning at event boundaries, preserving real-time delivery without exposing secrets. The agent gets a clean stream. The credential never enters its context, even if the upstream API echoes it back in an error response.

This matters because secret containment fails the moment an upstream service echoes a credential into the agent’s visible context. Even if an agent’s full context were extracted, there are no secrets to leak.

What this isn’t
#

Airlock is not an API gateway. No load balancing, no caching, no request transformation. It’s a ~10MB Go binary in a scratch Docker image with no shell and no OS. One instance per agent, one config file, one job: enforce a security boundary between an agent and the APIs it calls.

It doesn’t replace upstream key scoping where available. Use both. Independent layers fail independently.

So why not just use vendor permissions, fine-grained tokens, and careful tool design? Those controls help, but they are fragmented, inconsistent across systems, and often unavailable for internal APIs or third-party tools. Airlock gives you one enforcement layer that is local, reviewable, and independent of what each upstream platform happens to support.

The bigger pattern
#

If you’re building agents in a regulated environment, your compliance framework already requires that system access be scoped, auditable, and enforceable. Agents don’t get an exemption from those requirements just because the caller is a language model instead of a human.

The access control playbook hasn’t changed: never trust the client, default deny, grant minimum necessary access. The infrastructure to apply it to agents is what’s missing.

Three questions worth asking about your own agent infrastructure:

  1. Credential exposure: If your agent logged every outbound request header, what secrets would be in that log?
  2. Blast radius: What’s the worst API call your agent’s credentials authorize that you’d never want it to make?
  3. Tool governance: Can you enumerate every MCP tool your agents can call right now, and who approved each one?

Airlock is open source at github.com/realugbun/airlock .

Author
Jackson Atkins