A shared API key is not agent identity.
If two agents use the same key, your audit record says the same principal did both things. When something goes wrong, you cannot answer: who was the agent acting for? — and you cannot scope what each one is allowed to do.
Problem: capability spreads faster than identity
Most agent stacks start with one key in .env that every agent reads. Add a second agent (planner, executor, reviewer) and they all hold the same credential. Add MCP servers and each server call inherits the same ambient authority. Add a production database and the key that should only be used by the deploy agent is now readable by the PR-triage agent — because it can read any file the process can.
cirvix scan makes this visible: un governed runtimes · credential-readable paths · broad MCP scopes — the inventory of what ambient authority an agent on this machine already has without a policy.
What agent IAM actually means
Not a user-IAM translation. Three layers:
- Agent identity is (issuer, subject) — not email, not key, not hostname. Resolved via OIDC (Google, Entra, Okta). Email changes; (issuer, subject) does not alias.
- Authority is per-agent, default-deny — every tool call crosses
guard.wrap(tools, { agent: "pr-triage", rules }). Absence of a rule is not permission.forbidis terminal — no later rule lifts it. - Delegation is explicit, not impersonation — capability tokens + delegation produce an auditable chain of "who authorized whom", not "who faked whom". SCIM for provisioning, SSO for membership, SAML deliberately not supported.
import { guard, STARTER_RULES } from "@cirvix_ai/agent-control";
const tools = guard.wrap(myTools, {
agent: "pr-triage",
rules: STARTER_RULES
});
try {
await agent.invoke(input);
} catch (err) {
if (err instanceof CirvixDenied) {
console.log(err.policy, err.remediation, err.decisionId);
}
throw err;
}
Threat: the stolen-key lateral move
One compromised agent that holds a shared key can act as any agent that shares it. The control plane cannot distinguish them, the audit chain attributes all actions to the same principal, and revoking the key breaks every agent at once — so teams don't revoke, they rotate once and hope.
With per-agent identity: revoke pr-triage, not the key everyone holds. The decision record still shows precisely which agent was denied and why.
Cirvix enforcement: where identity binds
# 1 — which agents exist, governed? npx @cirvix_ai/agent-control scan --json # { runtimes: [{ label: "Claude Code", governed: true }, { label: "Cursor", governed: false }] } # 2 — what would this identity do with this tool? npx @cirvix_ai/agent-control check --agent pr-triage --action fs.write --resource prod/config.json # DENY — no rule permits pr-triage to write prod # 3 — gateway as identity boundary npx @cirvix_ai/agent-control gateway --servers ~/.cursor/mcp.json --policy cirvix.policy.json
The gateway, the guard.wrap middleware, and the policy DSL all resolve the same (agent, action, resource, environment) tuple. One fixture (packages/conformance) holds Node + Python to the same verdicts.
Honest limits
- Compromised IdP → compromised approvals. Cirvix does not replace an identity provider.
- Root on the endpoint is out of scope (resolved secrets in process memory).
- Identity without policy is still ambient authority. You must write the deny.
Search intent: "agent iam", "agent identity", "ai agent permissions" · Related: AI-Agent Security · Architecture · MCP Broad Scope