A CISO left a sharp comment on a recent post about my open-source non-human-identity scanner, and it’s worth unpacking because it names something specific about agent identities that the rest of the non-human world doesn’t share.

The observation: of all the signals you’d risk-tier a non-human identity on — privilege, credential age, ownership, exposure — autonomy, and the reach that comes with it, is the only one that can change without anyone touching the identity. Give an agent a new tool or connector and its blast radius grows, while privilege, credential age, and owner all look exactly the same. Their question: does a rescan catch that?

The honest answer is the interesting part.

Why a point-in-time scan can miss it

A posture scan reasons over the attributes an identity declares. For a classic service account, that’s stable — its permissions don’t change unless someone changes them. For an agent, reach is decoupled from the identity object:

  • Caught: if the new tool lands as a new scope, permission, or role assignment, the identity’s declared posture changes and a rescan re-tiers it.
  • Missed: if the tool is wired at the agent / MCP / orchestration layer and never becomes an identity-level permission, then privilege, credential age, and owner are genuinely unchanged — and a posture snapshot has no signal.

That second case is the CISO’s scenario exactly. Worse, a risk tier can be a lagging indicator here: an agent that’s already Tier 1 for autonomy and broad scope stays Tier 1 when it gains a payment-refund connector. The tier is “unchanged,” and the blast radius just doubled.

The fix is two design decisions

1. Treat the agent’s tool manifest as a first-class input. A scanner can’t diff reach it never captured. So the agent’s tools — its connectors, plugins, and MCP servers — have to be inventoried alongside its scopes, not left at the orchestration layer. Crucially, you read the declared manifest; you don’t infer it. It comes from wherever the agent’s capabilities are actually defined: its MCP server config, its agent-framework manifest (LangChain / Semantic Kernel / AutoGen tool lists), or its registered plugins and connectors in a platform like Copilot Studio or Microsoft Agent 365 / Entra Agent ID. nhi-scan ships a small collector for exactly this: point it at an agent’s connected servers and tools, and it emits the identity record with the manifest captured (tools namespaced server.tool) — so gathering reach is a documented step, not an exercise left to the reader.

2. Diff snapshots, don’t just re-tier them. Once the manifest is captured, you compare two scans and flag what moved — added tools, added scopes, escalations — and specifically surface the case that a tier hides: reach grew, tier unchanged. “The agent got a new connector” goes from an invisible change to a diffable one.

I built all of it into nhi-scan. A collector turns an agent’s connected servers/tools into an identity record with its tool manifest; nhi-scan diff <before> <after> then reports added/removed identities, tier escalations, and a dedicated “reach grew without a tier change” section. The end-to-end flow is one line — collect the manifest, snapshot it, diff two snapshots — so run it on a schedule or in CI, and reach creep stops being something you discover after an incident.

The larger point: posture vs. runtime

This is really an argument for why agents need continuous signals on top of point-in-time posture. Posture tells you what could go wrong — the standing privilege, the long-lived secret, the broad scope. Drift and runtime tell you when it’s changing — the new connector, the new scope, the expanding reach. A snapshot has inherent lag; an agent’s reach moves between snapshots.

It maps cleanly onto the control model I’ve written about: constrain the tools an agent may invoke (govern reach as a first-class thing, not a side effect of identity), and monitor continuously rather than trusting a periodic attestation. See A Control Framework for Non-Human & Agentic Identity for where these sit.

The takeaway I’d leave you with: for agents, stop treating reach as a property of the identity and start treating it as something that drifts. Inventory the tool manifest, diff it, and watch the delta — because for an autonomous agent, the delta is the risk.

Grateful for the question that prompted this — the best feedback makes the tool sharper.

Discussion

Comments are powered by Giscus / GitHub Discussions. They appear here once configured — see Configure Giscus in the project README and update GISCUS in src/consts.ts.