Everyone quotes the stat: machine identities outnumber humans in the enterprise by more than 80 to 1. It’s abstract until you actually enumerate them.

So I pointed nhi-scan — my open-source risk-tiering tool for non-human and agent identities — at a real Microsoft Entra tenant and counted. The result: 614 non-human identities — 586 service principals and 28 AI agents — versus a handful of human admins. The 80:1 number stopped being a slide and became a worklist.

Here’s what the scan found, and the lesson hiding inside it that made me change the tool itself.

Finding 1: Almost nothing had a clear owner

573 of the 614 identities had no assigned owner. On its face, that’s alarming — “improper offboarding” (OWASP NHI1) is the top non-human identity risk for a reason: an identity nobody owns is an identity nobody rotates, reviews, or decommissions.

But the raw number lies if you stop there. Broken down:

  • 485 were third-party / vendor-operated apps — ownership sits with the vendor; informational, not actionable.
  • 70 were platform-managed identities — the “owner” is the backing cloud resource, not a person.
  • 16 were genuinely tenant-owned application identities that actually need a human owner.

That last number is the one a security team can act on. The value wasn’t the 573 — it was separating the 16 that matter from the 557 that are noise. Non-human identity governance lives or dies on that distinction.

Finding 2: 53 “long-lived secrets” — and only 1 was real

This is the finding that changed how I build.

The first pass flagged 53 identities with long-lived secrets (OWASP NHI7) — the classic “un-rotated credential” risk. A team seeing 53 criticals would either panic or, worse, tune the alert out.

When I investigated, 52 of the 53 were Azure managed identities. Their “secrets” are platform-issued certificates that the cloud auto-rotates — they are never stored, never handled by a human, and structurally can’t be the stale-credential risk the finding implies. Exactly one was a genuine application credential worth rotating.

53 → 1. That’s not a rounding error; it’s the difference between a report a team trusts and one they ignore.

The lesson: a non-human-identity tool that treats managed identities like stored secrets will drown its users in false positives on day one. Risk tiering has to understand what kind of credential it’s looking at — not just that a credential exists. (Fixing this in the tool became its own story — more on that in a follow-up.)

Finding 3: Over-privilege — but not all of it is yours to fix

The scan surfaced 10 critical, over-privileged identities, three holding tenant-admin-class directory permissions. Sounds like a fire drill.

Context reframed it: 9 of the 10 were vendor / platform-operated apps — you don’t rescope those, you attest to them and alert on any new elevated consent. Exactly one was a tenant-owned application holding more privilege than it needed — and that one is the real action item: assign an owner, right-size the permissions.

The takeaway for anyone triaging NHI risk: elevated ≠ actionable. Separating “operated by someone else” from “owned by us” is what turns a scary list into a short one.

Finding 4: The AI agents were the healthiest thing in the tenant

The tenant had 28 AI agents across 21 blueprints — security-triage agents, threat-hunting and threat-intel agents, and agents built on multiple AI frameworks and clouds. This is the fastest-growing, least-understood identity class, so I expected the worst.

They were, in fact, the best-governed identities present: all federated (no stored secrets), read-only, and non-autonomous. The only issue was two orphaned agents left over from testing — sponsor them or offboard them.

That matters because it shows agent identity governance is achievable when it’s designed in from the start (federation, least privilege, no standing autonomy) — the opposite of the sprawl we inherited with service accounts.

The real payoff: 614 identities → a one-page worklist

The point of risk-tiering isn’t the big number. It’s the small one at the end. After tiering by privilege, ownership, credential type, and activity, 614 raw identities collapsed into a handful of concrete actions:

  • 1 application credential to rotate
  • 1 tenant-owned over-privileged app to right-size
  • 16 application identities that need a human owner
  • 59 managed identities unused for 90+ days to verify or delete
  • 2 orphaned agents to sponsor or retire
  • 9 vendor/platform apps to attest (not rescope) — and monitor for new elevated consent

That’s a Monday-morning list a team can actually execute — extracted from a population most organizations have never fully enumerated.

Why this matters

Non-human identity is the fastest-growing, least-governed attack surface in the enterprise, and the instinct is to reach for a scanner. But this scan is a reminder that counting isn’t the hard part — context is. A raw finding count (573 unowned! 53 stale secrets! 10 criticals!) is worse than useless if it can’t tell managed identities from stored secrets, vendor apps from your own, or elevated-but-attested from elevated-and-yours.

That’s the whole thesis behind the way I build in this space: risk models have to be honest about context, or they train people to ignore them.

Running nhi-scan against 600+ real identities didn’t just produce findings — it exposed a place where my own tool wasn’t context-aware enough, and I fixed it upstream. I’ll write that engineering story up separately.


nhi-scan is open source (MIT): github.com/rpmsft9/nhi-scan. It risk-tiers non-human and agent identities against the OWASP NHI Top 10, with drift detection for agent reach. Feedback and contributions welcome.

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.